爬虫提高:scrapy使用 | 爬虫 |《python学习之路》| python 技术论坛-金年会app官方网
scrapy项目实现流程
- 创建一个scrapy项目:
scrapy startproject myspider
- 生成一个爬虫:
scrapy genspider itcast "itcast.cn
- 提取数据:
完善spider,使用xpath等方法
- 保存数据:
pipeline中保存数据
创建scrapy项目
下面以抓取传智师资库来学习scrapy的入门使用: startproject <项目名字>`
创建爬虫
命令:scrapy genspider <爬虫名字> <允许爬取的域名>
完善spider
完善spider即通过方法进行数据的提取等操作
注意:
response.xpath
方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法extract()
返回一个包含有字符串的列表extract_first()
返回列表中的第一个字符串,列表为空没有返回none- spider中的parse方法必须有
- 需要抓取的url地址必须属于allowed_domains,但是start_urls中的url地址没有这个限制
- 启动爬虫的时候注意启动的位置,是在项目路径下启动
数据传递到pipeline
为什么要使用yield?
- 让整个函数变成一个生成器,有什么好处呢?
- 遍历这个函数的返回值的时候,挨个把数据读到内存,不会造成内存的瞬间占用过高
- python3中的range和python2中的xrange同理
注意:
- yield能够传递的对象只能是:
baseitem
,request
,dict
,none
完善pipeline
pipeline在settings中能够开启多个,为什么需要开启多个?
- 不同的pipeline可以处理不同爬虫的数据
- 不同的pipeline能够进行不同的数据处理的操作,比如一个进行数据清洗,一个进行数据的保存
pipeline使用注意点
- 使用之前需要在settings中开启
- pipeline在setting中键表示位置(即pipeline在项目中的位置可以自定义),值表示距离引擎的远近,越近数据会越先经过
- 有多个pipeline的时候,process_item的方法必须
return item
,否则后一个pipeline取到的数据为none值 - pipeline中process_item的方法必须有,否则item没有办法接受和处理
- process_item方法接受item和spider,其中spider表示当前传递item过来的spider
输出日志log的设置
为了让我们自己希望输出到终端的内容能容易看一些,我们可以在setting中设置log级别
在setting中添加一行(全部大写):log_level = "warning”
默认终端显示的是debug级别的log信息
scrapy实现翻页请求
对于要提取所有页面上的数据该怎么办?
回顾requests模块是如何实现翻页请求的:
- 找到下一页的url地址
- 调用requests.get(url)
思路:
- 找到下一页的url地址
- 构造url地址的请求,传递给引擎
实现翻页请求
使用方法
在获取到url地址之后,可以通过
scrapy.request(url,callback)
得到一个request对象,通过yield关键字就可以把这个request对象交给引擎具体使用
添加user-agent
同时可以再在setting中设置user-agent:
user_agent = 'mozilla/5.0 (macintosh; intel mac os x 10_12_5) applewebkit/537.36 (khtml, like gecko) chrome/59.0.3071.115 safari/537.36'
通过爬取腾讯招聘的页面的招聘信息,学习如何实现翻页请求
地址:
思路分析:
- 获取金年会app官方网首页的数据
- 寻找下一页的地址,进行翻页获取数据
scrapy.request的更多参数
scrapy.request(url[,callback,method="get",headers,body,cookies,meta,dont_filter=false])
注意:
- 括号中的参数为可选参数
- callback:表示当前的url的响应交给哪个函数去处理
- meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
- dont_filter:默认会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
定义item
定义item的原因:定义item即提前规划好哪些字段需要抓取,scrapy.field()仅仅是提前占坑,通过item.py能够让别人清楚自己的爬虫是在抓取什么,同时定义好哪些字段是需要抓取的,没有定义的字段不能使用,防止手误
使用item
item使用之前需要先导入并且实例化,之后的使用方法和使用字典相同
from yangguang.items import yangguangitem
item = yangguangitem() #实例化
scrapy的深入使用
scrapy shell的使用
scrapy shell是scrapy提供的一个终端工具,能够通过它查看scrapy中对象的属性和方法,以及测试xpath
使用方法:scrapy shell http://www.itcast.cn/channel/teacher.shtml
在终端输入上述命令后,能够进入python的交互式终端
小知识点:
- response.url:当前响应的url地址
- response.request.url:当前响应对应的请求的url地址
- response.headers:响应头
- response.body:响应体,也就是html代码,默认是byte类型
- response.requests.headers:当前响应的请求头
认识scrapy中的setting文件
为什么项目中需要配置文件
- 在配置文件中存放一些公共变量,在后续的项目中便便修改,注意其中的变量名一般全部大写
配置文件中的变量使用方法
- 导入即可使用
settings.py
中的重点字段和内涵user_agent
设置uarobotstxt_obey
是否遵守robots协议,默认是遵守concurrent_requests
设置并发请求的数量,默认是16个download_delay
下载延迟,默认无延迟cookies_enabled
是否开启cookie,即每次请求带上前一次的cookie,默认是开启的default_request_headers
设置默认请求头spider_middlewares
爬虫中间件,设置过程和管道相同downloader_middlewares
下载中间件
管道中的
open_spider
和close_spider
的方法在管道中,除了必须定义process_item之外,还可以定义两个方法:
open_spider(spider)
:能够在爬虫开启的时候执行一次close_spider(spider)
:能够在爬虫关闭的时候执行一次
所以,上述方法经常用于爬虫和数据库的交互,在爬虫开启的时候建立和数据库的连接,在爬虫关闭的时候断开和数据库的连接
crawlspider类的使用
crawlspider是什么
回顾之前的代码中,我们有很大一部分时间在寻找下一页的url地址或者是内容的url地址上面,这个过程能更简单一些么?
思路:
从response中提取所有的满足规则的url地址
自动的构造自己requests请求,发送给引擎
对应的crawlspider就可以实现上述需求,匹配满足条件的url地址,才发送给引擎,同时能够指定callback函数
认识crawlspider爬虫
创建crawlspdier爬虫的命令
scrapy genspider –t crawl itcast itcast.cn
观察爬虫内的默认内容
spider中默认生成的内容如下,其中重点在rules中
- rules是一个元组或者是列表,包含的是rule对象
- rule表示规则,其中包含
linkextractor
,callback
和follow
linkextractor
:连接提取器,可以通过正则或者是xpath来进行url地址的匹配callback
:表示经过连接提取器提取出来的url地址响应的回调函数,可以没有,没有表示响应不会进行回调函数的处理follow
:表示进过连接提取器提取的url地址对应的响应是否还会继续被rules中的规则进行提取,true表示会,flase表示不会
class itcast1spider(crawlspider):
name = 'itcast1'
allowed_domains = ['itcast.cn']
start_urls = ['http://itcast.cn/']
rules = (
rule(linkextractor(allow=r'items/'), callback='parse_item', follow=true),
)
def parse_item(self, response):
i = {}
#使用xpath进行数据的提取或者url地址的提取
return i
crawlspider使用的注意点
- 可以用命令创建一个crawlspider的模板,也可以手动创建
- crawlspider中不能再有以parse为名字的数据提取方法,这个方法被crawlspider用来实现基础url提取等功能
- 一个rule对象接收很多参数,首先第一个是包含url规则得到linkextractor对象,常用的还有callback(制定满足规则的url的解析函数的字符串)和follow(response中提取的链接是否需要跟进)
- 不指定callback函数的请求下,如果follow为true,满足该rule的url还会继续被请求
- 如果多个rule都满足某一个url,会从rules中选择第一个满足的进行操作
crawlspider的补充知识点
lindextractor更多常见参数:
allow:满足括号中”正则表达式”的url会被提取,如果为空,则全部匹配
deny:满足括号中”正则表达式”的url一定不提取(优先级高于allow)
allow_domains:会被提取的链接的domains
deny_domains:一定不会被提取链接的domains
restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接,即xpath满足范围内的url地址会被提取
spiders.rule常见参数:
link_extractor:是一个link extractor对象,用于定义需要提取的链接
callback:从link_extractor中每获取到链接时,参数所指定的值作为回调函数
follow:是一个布尔值,制定了根据该规则从response提取的链接是否需要跟进。如果callback为none,follow默认设置为true,否则默认为false
process_links:指定该spider中那个的函数将会被调用,从link_extractor中获取到链接列表时将会调用该函数,该方法主要用来过滤url
process_request:指定该spider中那个的函数将会被调用,该规则提取到每个request时都会调用该函数,用来过滤request
下载中间件和模拟登陆
scrapy中下载中间件的使用
使用方法
编写一个downloader middlewares
和我们编写一个pipeline一样,定义一个类,然后在setting中开启
downloader middlewares
默认的方法:process_request(self, request, spider):
- 当每个request通过下载中间件时,该方法被调用。
- 返回none值:继续请求
- 返回response对象:不在请求,把response返回给引擎
- 返回request对象:把request对象交给调度器进行后续的请求
process_response(self, request, response, spider):
- 当下载器完成http请求,传递响应给引擎的时候调用 - 返回resposne:交给process_response来处理 - 返回request对象:交给调取器继续请求
定义实现随机user-agent的下载中间件
class useragentmiddleware(object): def process_request(self,request,spider): agent = random.choice(agents) request.headers['user-agent'] = agent
定义实现随机使用代理的下载中间件
class proxymiddleware(object): def process_request(self,request,spider): proxy = random.choice(proxies) request.meta['proxy'] = proxy
user-agent池在这里
```python user_agents = [ "mozilla/5.0 (compatible; msie 9.0; windows nt 6.1; win64; x64; trident/5.0; .net clr 3.5.30729; .net clr 3.0.30729; .net clr 2.0.50727; media center pc 6.0)", "mozilla/5.0 (compatible; msie 8.0; windows nt 6.0; trident/4.0; wow64; trident/4.0; slcc2; .net clr 2.0.50727; .net clr 3.5.30729; .net clr 3.0.30729; .net clr 1.0.3705; .net clr 1.1.4322)", "mozilla/4.0 (compatible; msie 7.0b; windows nt 5.2; .net clr 1.1.4322; .net clr 2.0.50727; infopath.2; .net clr 3.0.04506.30)", "mozilla/5.0 (windows; u; windows nt 5.1; zh-cn) applewebkit/523.15 (khtml, like gecko, safari/419.3) arora/0.3 (change: 287 c9dfb30)", "mozilla/5.0 (x11; u; linux; en-us) applewebkit/527 (khtml, like gecko, safari/419.3) arora/0.6", "mozilla/5.0 (windows; u; windows nt 5.1; en-us; rv:1.8.1.2pre) gecko/20070215 k-ninja/2.1.1", "mozilla/5.0 (windows; u; windows nt 5.1; zh-cn; rv:1.9) gecko/20080705 firefox/3.0 kapiko/3.0", "mozilla/5.0 (x11; linux i686; u;) gecko/20070322 kazehakase/0.4.5" ]
使用scrapy进行模拟登陆
回顾之前的模拟登陆的方法
- requests是如何模拟登陆的?
- 直接携带cookies请求页面
- 找接口发送post请求存储cookie
- selenium是如何模拟登陆的?
- 找到对应的input标签,输入文字点击登录
scrapy来说,有两个方法模拟登陆:
1、直接携带cookie
2、找到发送post请求的url地址,带上信息,发送请求
scrapy携带cookie进行模拟登陆
携带cookie进行模拟登陆应用场景:
- cookie过期时间很长,常见于一些不规范的网站
- 能在cookie过期之前把搜有的数据拿到
- 配合其他程序使用,比如其使用selenium把登陆之后的cookie获取到保存到本地,scrapy发送请求之前先读取本地cookie
scrapy的start_requests方法的学习
scrapy中start_url是通过start_requests来进行处理的,其实现代码如下
def start_requests(self): cls = self.__class__ if method_is_overridden(cls, spider, 'make_requests_from_url'): warnings.warn( "spider.make_requests_from_url method is deprecated; it " "won't be called in future scrapy releases. please " "override spider.start_requests method instead (see %s.%s)." % ( cls.__module__, cls.__name__ ), ) for url in self.start_urls: yield self.make_requests_from_url(url) else: for url in self.start_urls: yield request(url, dont_filter=true)
所以对应的,如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写
start_request
方法并在其中手动添加上cookie
在settings中开启cookie_debug
在settings.py中通过设置cookies_debug=true
能够在终端看到cookie的传递传递过程
scrapy发送post请求
scrapy中发送post请求的方法 通过
scrapy.formrequest
能够发送post请求,同时需要添加fromdata
参数作为请求体,以及callback
yield scrapy.formrequest( "https://github.com/session", formdata={ "authenticity_token":authenticity_token, "utf8":utf8, "commit":commit, "login":"noobpythoner", "password":"zhoudawei123" }, callback=self.parse_login )
使用scrapy模拟登陆github
思路分析
找到post的url地址
点击登录按钮进行抓包,然后定位url地址为
https://github.com/session
找到请求体的规律
分析post请求的请求体,其中包含的参数均在前一次的响应中
验证是否登录成功
通过请求个人金年会app官方网主页,观察是否包含用户名
代码实现如下:
#spider/github.py # -*- coding: utf-8 -*- import scrapy import re class githubspider(scrapy.spider): name = 'github' allowed_domains = ['github.com'] start_urls = ['https://github.com/login'] def parse(self, response): authenticity_token = response.xpath("//input[@name='authenticity_token']/@value").extract_first() utf8 = response.xpath("//input[@name='utf8']/@value").extract_first() commit = response.xpath("//input[@name='commit']/@value").extract_first() yield scrapy.formrequest( "https://github.com/session", formdata={ "authenticity_token":authenticity_token, "utf8":utf8, "commit":commit, "login":"noobpythoner", "password":"***" }, callback=self.parse_login ) def parse_login(self,response): ret = re.findall("noobpythoner",response.text,re.i) print(ret)
scrapy进行表单提交
方法介绍
scrapy中具有一个方法:
scrapy.formrequest.from_response
能够自动的从响应中寻找form表单,然后把formdata中的数据提交到action对应的url地址中使用实例如下
def parse(self, response): yield scrapy.formrequest.from_response( response,#自动的从中寻找action对应的url地址 formdata={ "login":"noobpythoner", "password":"***" }, callback = self.parse_login )
使用
scrapy.formrequest.from_response
进行模拟登陆github