Scrapy中yield的使用

  • 背景
  • yield的理解
  • scrapy中的yield的使用
    • scrapy.Request对象
    • scrapy.Item对象
  • scrapy中的传值的问题
    • 从持久化数据源(数据库/表格)中获取数据
    • 使用cb_kwargs在request和callback回调函数之间进行传参
  • 参考

背景

yield和协程总是相伴出现。
scrapy使用yield进行数据解析和爬取request。

yield的理解

yield的解释都比较复杂,一段典型的yield的使用如下:

def foo():    print("starting...")while True:res = yield 4print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(g.send(7))

这边有几个要点:

  1. yield的一行跟return的用法基本比较接近;
  2. yield的函数(foo)被称为++生成器++;
  3. res = yield 4处包含了4个操作
    1. 向调用处抛出(返回)4
    2. 暂停,并等待调用处的nextsend恢复
    3. 接收调用处send发送进来的值
    4. 将接收到的值赋给等号左边
  4. 生成器接收到nextsend恢复后,从yield的下一句开始执行,
    1. 本例中调用next恢复后,从yield处继续往下执行,其中next调用带入的参数为None,因此从执行res = None继续往下;
    2. 本例中调用send恢复后,从yield处继续往下执行,其中yield在生成器的返回值为send带入的参数7

scrapy中的yield的使用

在scrapy中典型的yield场景主要是使用scrapy.Request对象和scrapy.Item对象。

scrapy.Request对象

def start_requests(self):urlfront = 'http://www.example.com/XYPT/score/scoreInfoList?objectType=1&pageSize=100&scoreUnitId='csv_reader = csv.reader(open("./Requirement.csv"))for line in csv_reader:#根据数据生成爬取地址url = urlfront + self.punishment_numberyield scrapy.Request(url=url, callback=self.parse2)

scrapy框架会去获得Requese对象指向的链接,并进行爬取请求,在请求完成后调用该对象的回调函数。
这里我们查表获取链接,并拼装,在循环内通过yield来发起请求,并且还将函数parse2注册为回调函数,parse2中应提取响应所需的数据。

scrapy.Item对象

#存储结构化数据
for company in response.css('tbody').css("tr"):field = company.css("td")yield {'Number': field[0].css("::text").get(),'CompanyName': field[1].css("a::text").get().split(" ")[-1],'UnifiedCreditCode': field[2].css("::text").get(),'Address': field[3].css("::text").get(),'EstablishmentNumber':  field[4].css("a::text").get().split(" ")[-1],'EIAEngineersNumber':  field[5].css("a::text").get().split(" ")[-1],'Status':  field[6].get().split(" ")[-1].split("<")[0],'PunishmentDetail':  field[7].css("a.amend-see::attr(href)").get().split("'")[-2],}

{}中间构建了一个scrapy.Item对象,scrapy框架会将这个对象传递给pipelines.py进行下一步处理,如果没有编写pipelines.py,就是单纯对item进行返回。
这里我们通过yield返回了一个8个key的scrapy.Item对象。

scrapy中的传值的问题

在scrapy中,callback同spider是在不同的进程中执行的,所以如果使用全局变量会遇到多进程读写的毛病。
对于这一点,我们有两种解决方案。

从持久化数据源(数据库/表格)中获取数据

这一块的作法是根据url中的关键字进行解码,采用解码后的结果从持久化数据源中进行查表并获取所需的关联数据。

def parse(self, response):punish_id = response.url.split("=")[-1]with open("./Requirement.csv") as csvfile:reader = csv.DictReader(csvfile)for row in reader:if row["PunishmentID"] == punish_id:unified_credit_code = row["UnifiedCreditCode"]company_code = row['技术单位名称']

上述例子是

  1. 从url中解码出punish_id
  2. 将csv文件读取为字典
  3. 搜索csv文件中对应的域"PunishmentID",获取相关的unified_credit_code和company_code

使用cb_kwargs在request和callback回调函数之间进行传参

    # 在Request发起端定义cb_kwargs,注意参数需要用dict来进行定义yield scrapy.Request(url=url, callback=self.parse2, cb_kwargs=dict(company_code=self.company_name, punish_id=self.punishment_number, unified_credit_code=self.unified_creditcode))#在callback函数中需要对应地声明cb_kwargs的参数
def parse2(self, response, company_code, punish_id, unified_credit_code):

这里,将全局变量self.company_name, self.punishment_numberself.unified_creditcode通过传值的方式参数传递给回调函数,并确保了上述全局变量被改变后,不影响回调函数中对这些值的使用。

注意:
Request.cb_kwargs是在scrapy 1.7 版本后被引入的。之前的版本使用Request.meta给回调函数传递信息,但meta的下属结构定义是固定的。1.7版本后,通常我们使用Request.cb_kwargs来处理用户信息,而Request.meta作为中间件和扩展组件的通信使用。

参考

https://towardsdatascience.com/web-scraping-with-scrapy-theoretical-understanding-f8639a25d9cd
https://docs.scrapy.org/en/latest/topics/request-response.html#topics-request-meta
https://www.cnblogs.com/chenxi188/p/10848690.html

Scrapy中的yield使用相关推荐

  1. python yield 惰性计算,用于scrapy中(美食杰爬虫为例)

    先说一下什么是python的惰性计算 惰性计算(Lazy evaluation)是指仅仅在真正需要执行的时候才计算表达式的值.充分利用其特性可以带来很多便利.yield的功能类似于return,但是不 ...

  2. Scrapy中的splash的安装应用

    Scrapy中的splash的安装应用 因为要去抓取部分经过JavaScript渲染的网页数据,所以使用scrapy中的Request返回的是没有经过渲染的网页代码, 因此我们就要运用Scrapy中的 ...

  3. Scrapy框架的学习(9.Scrapy中的CrawlSpider类的作用以及使用,实现优化的翻页爬虫)

    1.CrawlSpider类通过一些规则(rules),使对于链接(网页)的爬取更具有通用性, 换句话说,CrawlSpider爬虫为通用性的爬虫, 而Spider爬虫更像是为一些特殊网站制定的爬虫. ...

  4. Scrapy中Request的回调函数不执行

    一. 举例 def parse(self, response):...yield Request(url=parse.urljoin(response.url, title_herf), meta=m ...

  5. python捕获所有异常状态_如何在scrapy中捕获并处理各种异常

    前言 使用scrapy进行大型爬取任务的时候(爬取耗时以天为单位),无论主机网速多好,爬完之后总会发现scrapy日志中"item_scraped_count"不等于预先的种子数量 ...

  6. 如何在scrapy中捕获并处理各种异常

    前言     使用scrapy进行大型爬取任务的时候(爬取耗时以天为单位),无论主机网速多好,爬完之后总会发现scrapy日志中"item_scraped_count"不等于预先的 ...

  7. [Scrapy使用技巧] 如何在scrapy中捕获并处理各种异常

    前言     使用scrapy进行大型爬取任务的时候(爬取耗时以天为单位),无论主机网速多好,爬完之后总会发现scrapy日志中"item_scraped_count"不等于预先的 ...

  8. Scrapy中对xpath使用re

    Scrapy中使用xpath时,根据xpath的语法不一定能得到想要的. 如下面的html源码: 1 <div class="db_contout"> <div ...

  9. scrapy中集成selenium+浏览器池实现selenium的并发爬取LCSC网站中非结构化表格数据+异步存储进mysql+完整代码

    爬取https://lcsc.com/products/Connectors_365.html这个网址下所有的表格数据. 蓝色的都是要爬取的子页面,要爬取子页面里面的表格数据 ,表格数据如下: 右上角 ...

最新文章

  1. Open vSwitch(OVS)源码编译Ubuntu16.04,Linux内核版本4.15
  2. lg gram 笔记本 linux,lg gram 15笔记本使用雨林木风u盘安装win7系统教程?
  3. Windows下MySql安装【图文】
  4. Object类、常用API
  5. 2.1.3 计算机网络之编码与调制
  6. 按揭买的房,房产证为什么要放在银行,自己要用房产证怎么办?
  7. 手机子王掩码和网关查找_C程序使用位掩码查找奇数或偶数
  8. 新思科技与台积电开发基于N4P制程的最广泛IP核组合
  9. 简单几步把Spring Boot 项目部署到 K8S,步骤来了!
  10. i5-8300h和i7-8750h 那个好
  11. 天行健,君子以自强不息;地势坤,君子以厚德载物
  12. 一篇会改变身处职场的你思维的一篇文章
  13. utools沙拉查词插件 | windows划词翻译
  14. requests模块的异常处理
  15. html5网页流行色,Pantone 2018流行色:紫外光色(附紫色的UI设计作品)
  16. 一起来了解木马的七种分类
  17. Xenomai——实现一个GNU/Linux上的RTOS的仿真框架
  18. 快速打开浏览倾斜摄影数据教程
  19. 利用matlab工具箱的pid参数科学整定方法
  20. pygame简单弹弹球游戏(弹来弹去)

热门文章

  1. win10 hyper ubuntu18 共享文件夹
  2. 信号与系统郑君里上册pdf_信号与系统(上册)
  3. 阿尔伯塔大学的计算机科学专业好吗,阿尔伯塔大学哪个专业好?三大热门方向成就高薪未来...
  4. html5嵌套css语言,HTML5和CSS3
  5. linux ping不允许的操作,linux – ping:sendmsg:不允许操作(有时)
  6. java 扫描所有子类_java获取全部子类或接口的全部实现
  7. php防止恶意充值,php防止恶意刷新与刷票的方法
  8. Mysql 中的事件//定时任务
  9. img加载不出来,给个默认图片。
  10. SQL Server 2005客户端安装和端口设置