URL的组成 URL地址由协议头、服务器地址、文件路径三部分组成
协议头(Protocol Head) 协议头指定使用的传输协议,用于告诉浏览器如何处理将要打开的文件。不同的协议表示不同的资源查找以及传输方式。网络上常用的协议如表1所示。
表1 URL常见的协议 其中最常用的是HTTP协议和HTTPS协议,分别由协议头http和https指定。
服务器地址(Hostname或者IP)和端口(Port)
路径(Path) 路径是由0或者多个“/”符号隔开的字符串,一般用于指定本次请求的资源在服务器中的位置。
爬取第一个网站 目标网站: 百度首页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import urllib.requesturl = "https://www.baidu.com/" headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 " "Safari/537.36" } request = urllib.request.Request(url=url, headers=headers) response = urllib.request.urlopen(request) content = response.read().decode("utf-8" ) print (response.getcode())
结果:
常见http状态码 https://www.runoob.com/http/http-status-codes.html
Post请求百度翻译
构建请求对象即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import urllib.requestimport urllib.parseimport jsonurl = 'https://fanyi.baidu.com/sug' data = { 'kw' : 'hello' , } headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 ' 'Safari/537.36' } data = urllib.parse.urlencode(data).encode('utf-8' ) request = urllib.request.Request(url=url, data=data, headers=headers) response = urllib.request.urlopen(request) res = response.read().decode() res = json.loads(res) print (res)
运行结果
爬取指定城市肯德基的相关信息 代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import urllib.requestimport urllib.parseimport jsondef create_request (page ): """ 创建请求对象 :param page: 页码 :return: 请求对象 """ baseurl = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname' data = { 'cname' : '柳州' , 'pid' : '' , 'pageIndex' : page, 'pageSize' : '10' , } data = urllib.parse.urlencode(data).encode('utf-8' ) headers = { 'Cookie' : '自己的Cookie' , 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/114.0.0.0 Safari/537.36' } request = urllib.request.Request(url=baseurl, data=data, headers=headers) return request def get_content (request ): response = urllib.request.urlopen(request) content = response.read().decode('utf-8' ) return content def down_load (page, content ): with open ('D:/project_code_file/python/pythonSpider/data/' + '柳州肯德基_' + str (page) + '.json' , 'w' , encoding='utf-8' ) as f: f.write(content) if __name__ == '__main__' : start_page = int (input ('请输入起始页码:' )) end_page = int (input ('请输入终止页码:' )) for page in range (start_page, end_page + 1 ): request = create_request(page) content = get_content(request) down_load(page, content)
结果:
Cookie的简单使用 cookie简介
Cookie 是通过浏览器将服务器返回的数据保存在本地的一小块数据(一般小于4kb)。当浏览器发送请求且浏览器存在 Cookie 时,浏览器会自动在请求头携带上 Cookie 数据。引入 Cookie 的意义是因为 HTTP 的请求是无状态的,如:浏览器发出的请求服务器没办法区分浏览器用户身份以及用户的相关操作状态(可以通过 Cookie 传递这些信息)。最开始 Cookie 被作为唯一的存储手段,但是因为浏览器的每次请求都会携带上 Cookie,会带来额外的开销,而且存储量比较小,所以后来浏览器推出了新的 Api(web stoeage Api和 indexedDb)。
cookie使用场景
会话状态管理(如用户登录状态、及其他需要记录的信息)
个性化设置(如用户自定义设置)
浏览器追踪行为(如追踪分析用户行为)
实例 使用cookie进入微博登录状态的页面(获取的cookie是以及登录过微博之后的cookie)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import urllib.requestimport urllib.parseurl = 'https://weibo.com/u/5887067753' headers = { 'Cookie' : '自己的Cookie' , 'Referer' : 'https://weibo.com/set/index' , 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 ' 'Safari/537.36' , } request = urllib.request.Request(url=url, headers=headers) response = urllib.request.urlopen(request) content = response.read().decode('gb2312' ) with open ('D:/project_code_file/python/pythonSpider/html/weibo.html' , 'w' , encoding='gb2312' ) as fp: fp.write(content)
效果:
代理服务器 代理的常用功能
突破自身ip的访问限制,访问国外站点
访问一些单位或团体内部资源
提高访问速度
隐藏真实ip
代码配置代理
创建Reuqest对象
创建ProxyHandler对象
用handler对象创建opener对象
使用opener.open函数发送请求
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import urllib.requesturl = 'https://www.baidu.com/s?ie=UTF-8&wd=ip' headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 ' 'Safari/537.36' } proxies = { 'http' : 'ip:port' , } request = urllib.request.Request(url=url, headers=headers) handler = urllib.request.ProxyHandler(proxies=proxies) opener = urllib.request.build_opener(handler) response = opener.open (request) content = response.read().decode('utf-8' ) with open ('D:/project_code_file/python/pythonSpider/html/ip.html' , 'w' , encoding='utf-8' ) as fp: fp.write(content)
Xpath的简单使用
使用到的python模块为lxml,一般是:from lxml import etree
结合浏览器插件:XPath Helper使用(具体安装自己查),元素定位很方便,敏感肌也能用
长这样:
虽然有XPath Helper,基本语法还是需要学一学的
下面针对这个html文件,进行简单的使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" /> <title > Title</title > </head > <body > <ul > <li id = "l1" class ="c1" > 百度</li > <li id = "l2" > 谷歌</li > <li id = "c3" > 必应</li > <li id = "c4" > 搜狗</li > </ul > <ul > <li id = "l3" > 北京</li > <li id = "l4" > 上海</li > <li > 广州</li > <li > 深圳</li > </ul > </body > </html >
python代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from lxml import etreetree = etree.parse('D:/project_code_file/python/pythonSpider/html/17xpath的基本使用.html' ) li_list = tree.xpath('//body//li/text()' ) print (li_list)li_list = tree.xpath('//li[@id]/text()' ) print (li_list)li_list = tree.xpath('//li[@id="l1"]/text()' ) print (li_list)li_list = tree.xpath('//li[@id="l1"]/@class' ) print (li_list)li_list = tree.xpath('//li[contains(@id,"l")]/text()' ) print (li_list)
requests模块的使用 简介 一个类型,六个属性 一个类型指的是get方法返回的是一个Response类型的对象 六个属性是值Response中的六个属性,分别是
设置响应的编码格式:response.encoding = ‘编码格式’
返回网页内容:response.text
返回网页的url:response.url
返回网页的二进制数据:response.content
返回响应头:response.headers
get请求简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import requestsurl = 'https://www.baidu.com/s?' headers = { 'Cookie' : 'Cookie' , 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 ' 'Safari/537.36' , } data = { 'wd' : '北京' } response = requests.get(url=url, params=data, headers=headers) response.encoding = 'utf-8' response_text = response.text print (response_text)
post请求简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import requestsimport jsonurl = 'https://fanyi.baidu.com/sug' headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36' } data = { 'kw' : 'eye' } response = requests.post(url=url, data=data, headers=headers) content = response.text dict_content = json.loads(content) print (dict_content)
综合案例(登录古诗文网)
抓取登录接口常用方法:打开目标网站的登录界面>>>F12>>>Network>>>在网页输入错误的密码并且登录>>>找登录接口>>>分析
开始干活:分析Form Data的数据,第一个__VIEWSTATE和第二份__VIEWSTATEGENERATOR数据看不懂,不知道哪里来的,先不着急,往下看,from应该是固定的,这个没问题,再往下看,只有code是随机的,那我们要怎样获取code呢?很简单,验证码是在网页中的,那我们把这张图片弄到手解析不就完了?
这下好了,验证码的URL有了,还愁获取不到验证码信息吗!再来解决数据1和数据2的问题,一般这种找不到的信息都在网页源码当中ctrl f自己找一找看看
简单示例, 没有使用到验证码图片解析,是比较笨的用手输入的,学过的朋友可以自己写一个来用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import requestsfrom bs4 import BeautifulSouppost_url = 'https://so.gushiwen.cn/user/login.aspx?from=http%3a%2f%2fso.gushiwen.cn%2fuser%2fcollect.aspx' url = 'https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx' code_url = 'https://so.gushiwen.cn/RandCode.ashx' headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 ' 'Safari/537.36' } response = requests.get(url=url, headers=headers) content = response.text soup = BeautifulSoup(content, 'lxml' ) viewstate = soup.select('#__VIEWSTATE' )[0 ].attrs.get('value' ) viewstategenerator = soup.select('#__VIEWSTATEGENERATOR' )[0 ].attrs.get('value' ) session = requests.session() content_code = session.get(url=code_url, headers=headers).content with open ('D:\project_code_file\python\pythonSpider\img\code.jpg' , 'wb' ) as f: f.write(content_code) code = input ("请输入验证码:" ) post_data = { '__VIEWSTATE' : viewstate, '__VIEWSTATEGENERATOR' : viewstategenerator, 'from' : 'http://so.gushiwen.cn/user/collect.aspx' , 'email' : 'your email' , 'pwd' : 'your passwd' , 'code' : code, 'denglu' : '登录' } response_post = session.post(url=post_url, headers=headers, data=post_data) content_post = response_post.text with open ('D:\project_code_file\python\pythonSpider\html\gushiwen.html' , 'w' , encoding='utf-8' ) as f: f.write(content_post)
selenium模块的使用 简介
Selenium 是一种开源工具,用于在 Web 浏览器上执行自动化测试(使用任何 Web 浏览器进行 Web 应用程序测试) 也可以应用于爬虫,对于一些数据,类似购物网站的限时秒杀部分的数据,普通的爬虫程序无法获取该部分数据,当我们使用真实的浏览器去访问的时候就能获取到。而selenium就能帮助我们实现这一功能
环境准备
需要对应的浏览器驱动,这里使用的是chromedriverchromedriver.exe 点我获取驱动
驱动直接拖入项目文件夹下,放在别处要注意编码时的路径
需求
访问百度,并且在百度的搜索框上输入“周杰伦”,并且点击搜索按钮执行该操作
编码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from selenium import webdriverfrom selenium.webdriver.chrome.options import Optionsdef share_chrome (): chrome_options = Options() chrome_options.add_argument('--headless' ) chrome_options.add_argument('--disable-gpu' ) path = r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe' chrome_options.binary_location = path browser = webdriver.Chrome(chrome_options=chrome_options) return browser url = 'https://www.baidu.com' browser = share_chrome() browser.get(url) text = browser.find_element_by_id('kw' ) text.send_keys('周杰伦' ) btn = browser.find_element_by_id('su' ) btn.click() sleep(2 ) browser.save_screenshot('baidu.png' )
说明
此过程是隐式的。如何证明已经完成了此过程?具体可以看第29-30行代码
scrapy爬虫框架入门 简介
scrapy是什么?
scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘、信息采集、等方面
scrapy的安装
pip install scrapy
如果出现错误,十有八九应该是没配置twisted的问题
scrapy项目的创建
scrapy startproject 项目名(不能以数字开头,也不能包含中文)
创建爬虫文件,要在项目的spiders文件夹下创建爬虫文件
cd .\项目名称\项目名称\spiders
scrapy genspider 爬虫文件的名字(不用带.py后缀) 爬取网站的域名
scrapy crawl 爬虫文件的名字
注意:要在spiders文件夹下执行
scrapy_demo 项目的名字
scrapy_demo 项目的名字,也是python软件包 spiders 爬虫文件夹,也是python软件包init .py demo.py 爬虫文件,核心功能文件init .py items.py 用于存储爬取的数据 middlewares.py 中间件,用来处理请求和响应 pipelines.py 管道文件,用来处理爬取的数据 settings.py 配置文件 用来配置项目的一些信息,比如:UA scrapy.cfg
scrapy框架结构
scrapy引擎
自动运行,不用管
scrapy下载器
引擎给到对象和数据,并履行数据下载的职责
spiders
spiders类定义了如何爬取某个网站,包括了爬取的方式,以及如何从网页的内容中提取结构化数据。换句话说,spiders是我们定义爬取动作以及分析某个网页的地方
scrapy 调度器
爬虫框架的系统调度,不用管
scrapy管道
最终处理数据的管道,会预留接口供我们处理数据
工作原理
爬虫文件中常用的方法、属性
首先核心爬虫文件中最核心的东西我个人觉得应该是response对象,response对象中包含了爬取网页的所有信息。获取自己想要的数据,就得熟悉该对象的属性还有方法
常用属性
response.body 获取响应体,二进制数据
response.text 获取响应体的文本
response.url 获取url
response.status 获取响应状态码
response.encoding 获取响应体的编码
response.request 获取请求对象
response.headers 获取响应头
常用方法
response.xpath(xpath路径) 使用xpath路径查询特定元素,返回一个selector列表对象
selector对象中常用的有extract()方法,该方法可以提取selector对象的值,使用xpath请求到的对象是一个selector对象,需要进一步使用extract()方法拆解成unicode字符串。同样的,常用的还有extract_first()方法,见名知意,该方法会提取selector对象中的第一个值。需要注意的是,每一个selector对象可以多次调用xpath方法。
yield
带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代 时,从上一次迭代遇到的yield后面的代码(下一行)开始执行
简要理解:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始
案例(当当网) 需求
获取该网页书的图片还有书名、价格https://category.dangdang.com/cp01.01.02.00.00.00.html 实现多条管道下载 多页数据下载
操作步骤
dangdang.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import scrapyfrom scrapy_dangdang_41.items import ScrapyDangdang41Itemclass DangdangSpider (scrapy.Spider): name = 'dangdang' allowed_domains = ['category.dangdang.com' ] start_urls = ['https://category.dangdang.com/cp01.01.02.00.00.00.html' ] base_url = 'https://category.dangdang.com/pg' page_num = 1 tail_url = '-cp01.01.02.00.00.00.html' def parse (self, response ): li_list = response.xpath('//ul[@id="component_59"]/li' ) for li in li_list: src = li.xpath('.//img/@data-original' ).extract_first() if src: src = src else : src = li.xpath('.//img/@src' ).extract_first() name = li.xpath('.//img/@alt' ).extract_first() price = li.xpath('.//p[@class="price"]/span[1]/text()' ).extract_first() book = ScrapyDangdang41Item(src=src, name=name, price=price) yield book if self .page_num < 100 : self .page_num += 1 url = self .base_url + str (self .page_num) + self .tail_url yield scrapy.Request(url=url, callback=self .parse)
items.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import scrapyclass ScrapyDangdang41Item (scrapy.Item): src = scrapy.Field() name = scrapy.Field() price = scrapy.Field()
pipelines.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 from itemadapter import ItemAdapterimport requestsclass ScrapyDangdang41Pipeline : def open_spider (self, spider ): print ('爬虫开始了' ) self .fp = open ('D:\\project_code_file\\python\\pythonSpider\\data\\book.json' , 'w' , encoding='utf-8' ) def process_item (self, item, spider ): self .fp.write(str (item) + '\n' ) return item def close_spider (self, spider ): print ('爬虫结束了' ) self .fp.close() class DangDangDownloadPipeline : def process_item (self, item, spider ): src = "http:" + item['src' ] res = requests.get(src) img_data = res.content img_name = item['name' ] + '.jpg' img_path = 'D:\\project_code_file\\python\\pythonSpider\\img\\books\\' + img_name with open (img_path, 'wb' ) as f: f.write(img_data) return item
settings.py
把管道开启,并且把ROBOTSTXT_OBEY注释掉,或者设置为False即可 管道开启方法:将Configure item pipelines那部分注释去掉就好,注意观察这里新增了一条管道,对应pipelines.py新增的类
1 2 3 4 5 6 7 ITEM_PIPELINES = { 'scrapy_dangdang_41.pipelines.ScrapyDangdang41Pipeline' : 300 , 'scrapy_dangdang_41.pipelines.DangDangDownloadPipeline' : 301 , }
运行项目(注意一定要在项目的spiders目录下执行该命令!)
scrapy crawl dangdang
结果:(还没爬完…..做个测试即可)
CrawlSpider 简介
继承自scrapy.Spider 区别:CrawlSpider可以自定义规则,再解析html内容的时候,可以根据链接规则,提取出指定的链接,然后再向这些链接发送请求,意思是爬取了网页之后,需要提取链接在此爬取,使用CrawlSpider是非常合适的
链接提取器 1 2 3 4 scrapy.linkextractors.LinkExtractor( allow = (正则表达式 提取符合正则的链接) restrict_xpaths = (xpath, 提取符合xpath规则的链接) )
使用样例
正则: link = LinkExtractor(allow=r’正则表达式’)
xpath:link = LinkExtractor(restrict_xpaths=r’xpath表达式’)
提取链接 link.extract_links(response)
注意事项 follow = bool bool表示是否跟进,就是是否按照提取链接规则进行提取 原理图
案例(CrawlSpider 读书网) 需求 读书网数据入库,使用到mysql数据库
操作步骤
创建项目
scrapy startproject scrapy_readbook_43
跳转到spiders目录下
cd .\scrapy_readbook_43\scrapy_readbook_43\spiders
创建爬虫文件
scrapy gensipder -t crawl readbook www.dushu.com
编码
readbook.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import scrapyfrom scrapy.linkextractors import LinkExtractorfrom scrapy.spiders import CrawlSpider, Rulefrom scrapy_readbook_43.items import ScrapyReadbook43Itemclass ReadbookSpider (CrawlSpider ): name = 'readbook' allowed_domains = ['www.dushu.com' ] start_urls = ['https://www.dushu.com/book/1188_1.html' ] rules = ( Rule(LinkExtractor(allow=r'/book/1188_\d+\.html' ), callback='parse_item' , follow=True ), ) def parse_item (self, response ): img_list = response.xpath('//div[@class="bookslist"]//img' ) author_list = response.xpath('//div[@class="book-info"]/p[1]/text()' ).extract() i = 0 for img in img_list: photo_url = img.xpath('./@data-original' ).extract_first() book_name = img.xpath('./@alt' ).extract_first() author = author_list[i] i += 1 book = ScrapyReadbook43Item(photo_url=photo_url, book_name=book_name, author=author) yield book
items.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import scrapyclass ScrapyReadbook43Item (scrapy.Item): photo_url = scrapy.Field() book_name = scrapy.Field() author = scrapy.Field()
pipelines.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 from itemadapter import ItemAdapterfrom pymysql import Connectionclass ScrapyReadbook43Pipeline : def open_spider (self, spider ): self .fp = open ('readbook.json' , 'w' , encoding='utf-8' ) def process_item (self, item, spider ): self .fp.write(str (item) + '\n' ) return item def close_spider (self, spider ): self .fp.close() class MysqlPipeline : def __init__ (self ): self .cursor = None self .connect = None def open_spider (self, spider ): self .connect_database() def connect_database (self ): self .connect = Connection( host='localhost' , port=3306 , user='root' , password='123456' , autocommit=True , ) self .connect.select_db('spider01' ) def process_item (self, item, spider ): self .cursor = self .connect.cursor() sql = "insert into books(book_name, author, photo_url) values('{}', '{}', '{}')" .format (item['book_name' ], item['author' ], item['photo_url' ]) self .cursor.execute(sql) return item def close_spider (self, spider ): self .cursor.close() self .connect.close() print ("数据库连接关闭" )
settings.py
开启管道即可
1 2 3 4 5 6 ITEM_PIPELINES = { 'scrapy_readbook_43.pipelines.ScrapyReadbook43Pipeline' : 300 , 'scrapy_readbook_43.pipelines.MysqlPipeline' : 301 , }
在settings.py中也可以指定日志的显示形式 比如加入LOG_FILE = '文件名.log'
项目运行的时候就不会在控制台输出一堆东西了,而是以log文件的形式保存了起来
结果 数据库
json文件