python爬虫scrapy之请求传参、使用selenium和CrawlSpider

请求传参

我们在spider中经常使用了两个或多个方法来用作数据解析,且每个都是解析不同的数据内容,那我们的item又只能实例化一次,我们要怎么把item类型对象分配到不同的方法中呢?

这就要用到请求传参。

yield  scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})

可以将meta字典传递给请求对应的回调函数

回调函数怎么接收item?

通过response来接收item

item = response.meta['item'] 

然后就是正常的将要存储的内容封装到item对象中,最后提交给管道进行持久化存储的操作。

使用selenium

当我们使用scrapy爬取的数据是动态加载的怎么办呢?

之前使用requests时,遇到动态加载的数据我们可以使用selenium,那scrapy我们能用吗,答案是可以的。

我们把request请求给下载器时,不是要经过下载中间件吗,然后下载器在把下载好的页面数据返回给引擎,但这里的页面数据是没有包含动态加载数据的,那这些页面数据对我们来说是不是没用,所以我们就要在下载器中间件中重写下载中间件的process_response方法,让该方法对没有包含动态加载数据的响应对象进行拦截,并篡改response中存储的页面数据。

首先在spider中写一个方法实例化一个浏览器对象。

def __init__(self):
    self.bro = webdriver.Edge()

写一个 方法关闭浏览器,且是在爬虫结束时。

def closed(self,spider):
    self.bro.quit()

然后在Middlewares中需要导入 HtmlResponse类, 这个类是用来将响应数据包装成符合HTTP协议形式。

from scrapy.http import HtmlResponse 

再看看 下载中间件中process_response方法

def process_request(self, request, spider):

    return None

其中request: 响应对象所对应的请求对象

response: 拦截到的响应对象

spider: 爬虫文件中对应的爬虫类,可以通过这个参数拿到爬虫类中的一些属性或方法

我们要获取在爬虫类定义的浏览器对象

bro = spider.bro

 然后进行请求发送

bro.get(spider.request.url)
sleep(2) # 等待加载, 可以用显示等待来优化。
page_text = bro.page_source  #包含了动态加载的数据。

再实例化一个新的响应对象(包含动态加载数据),代替原来旧的响应对象(不包含动态加载数据)

new_reponse = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)

return new_reponse

最后再配置文件中开启下载中间件DOWNLOADER_MIDDLEWARES

 

CrawlSpider

CrawlSpider,继承自Spider, 爬取网站常用的爬虫,其定义了一些规则(rule)方便追踪或者是过滤连接。

创建CrawlSpider输入 scrapy genspider -t crawl <爬虫文件名> <域名>。

初始化和spider差不多,多了个rules,里面有个Rule是规则解析器,LinkExtractor是连接提取器。

连接提取器:根据指定规则进行指定连接的提取,这里的规则就是正则表达式,写在allow中。

规则解析器:将连接提取器提取到的连接进行指定规则的解析操作,这里的规则就是callback。

当连接提取器提取到连接之后会自动的进行request请求发送,这个链接所对应的页面源码数据,都会由callback所指定的回调函数进行数据解析。

follow:指定了根据该规则从response提取的链接是否需要跟进,默认为True。

就是连接提取器提取到到的连接,然后在这个连接对应的页面源码中可以继续用连接提取器提取连接,有点套娃的意思,不过这样能实现对整个网站数据爬虫的操作。

其中parse_item中的response参数就是连接进行request请求之后的响应对象。

如果有不同的连接要提取就写两个规则解析器,两个连接提取器,一个规则解析器只能对应一个连接提取器。

link = LinkExtractor(allow=r'id=1&page=\d+')
link_detail = LinkExtractor(allow=r'index?id=\d+')

rules = (
    Rule(link, callback='parse_item', follow=True),
    Rule(link_detail, callback='parse_detail'),
)

CrawlSpider中不能请求传参,因为这里url都是自动发请求的。所以只能不同方法中解析到的数据放到不同的item中,在items中要写多个class item类。 

但是最后我们提交了两个item给管道,管道怎么区分是哪个item呢?

我们可以使用一个if语句来判断

if item.__class__.__name__=='DetailItem'              

 

这里只是介绍了一些常用的操作和方法,还有很多的方法和操作,大家感兴趣的话可以去看看文档。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值