百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Scrapy 爬虫框架组件详细介绍(二)

ccwgpt 2024-09-20 13:21 41 浏览 0 评论

1 Scrapy 爬虫框架组件详细介绍(二)

1.1 CrawlSpiders

20.1.1 爬虫CrawlSpiders类介绍

CrawlSpiders 类它是 Spider 的派生类,Spider 类的设计原则是只爬取 start_url 列表中的网页,而 CrawlSpider 类定义了一些规则( rule )来提供跟进 link 的方便机制,从爬取的网页中获取 link,并继续爬取工作,比Spiders 类模板爬虫更加适合。

前面案例创建爬虫,使用的命令如下:

scrapy genspider tencents " tencent.com "

默认使用”basic”template(模板)去创建爬虫。

如果想创建 CrawlSpider 类爬虫,可以通过下面的命令指定 crawl 模板可以快速创建 CrawlSpider 模板的爬虫。

scrapy genspider -t crawl tencents " tencent.com "

【-t 】: 指定模板。

例子:

在 DOS 下切换到下面目录。

D:\scrapy_project\tencent\tencent\spiders

执行命令:

scrapy genspider -t crawl tencents " tencent.com "

注意:命令创建的时候,爬虫文件名不能和作业域名相同,可以创建之后再改回来。

查看生成的 tencent.py 爬虫文件。

import scrapy

from scrapy.linkextractors import LinkExtractor

from scrapy.spiders import CrawlSpider, Rule

class TencentSpider(CrawlSpider):

name = 'tencent'

allowed_domains = [' tencent.com ']

start_urls = ['http:// tencent.com /']

rules = (

Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),

)

def parse_item(self, response):

i = {}

#i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()

#i['name'] = response.xpath('//div[@id="name"]').extract()

#i['description'] = response.xpath('//div[@id="description"]').extract()

return i

从生成的 tencent.py 爬虫文件和之前的Spider基类爬虫文件比较,多了如下几部分内容:

(一)需要导入 LinkExtractor、CrawlSpider、 Rule库

from scrapy.linkextractors import LinkExtractor

from scrapy.spiders import CrawlSpider, Rule

(二)爬虫类继承的是 CrawlSpider 类

(三)增加了 rules 。

(四)增加了 LinkExtractor(allow=r'Items/')

(五)新增加了一个回调函数 parse_item(self, response)

20.1.2 CrawlSpider源码

查看CrawlSpider源码。

class CrawlSpider(Spider):

rules = ()

def __init__(self, *a, **kw):

super(CrawlSpider, self).__init__(*a, **kw)

self._compile_rules()

def parse(self, response):

return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)

def parse_start_url(self, response):

return []

def process_results(self, response, results):

return results

def _build_request(self, rule, link):

r = Request(url=link.url, callback=self._response_downloaded)

r.meta.update(rule=rule, link_text=link.text)

return r

def _requests_to_follow(self, response):

if not isinstance(response, HtmlResponse):

return

seen = set()

for n, rule in enumerate(self._rules):

links = [lnk for lnk in rule.link_extractor.extract_links(response)

if lnk not in seen]

if links and rule.process_links:

links = rule.process_links(links)

for link in links:

seen.add(link)

r = self._build_request(n, link)

yield rule.process_request(r)

def _response_downloaded(self, response):

rule = self._rules[response.meta['rule']]

return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)

def _parse_response(self, response, callback, cb_kwargs, follow=True):

if callback:

cb_res = callback(response, **cb_kwargs) or ()

cb_res = self.process_results(response, cb_res)

for requests_or_item in iterate_spider_output(cb_res):

yield requests_or_item

if follow and self._follow_links:

for request_or_item in self._requests_to_follow(response):

yield request_or_item

def _compile_rules(self):

def get_method(method):

if callable(method):

return method

elif isinstance(method, six.string_types):

return getattr(self, method, None)

self._rules = [copy.copy(r) for r in self.rules]

for rule in self._rules:

rule.callback = get_method(rule.callback)

rule.process_links = get_method(rule.process_links)

rule.process_request = get_method(rule.process_request)

@classmethod

def from_crawler(cls, crawler, *args, **kwargs):

spider = super(CrawlSpider, cls).from_crawler(crawler, *args, **kwargs)

spider._follow_links = crawler.settings.getbool(

'CRAWLSPIDER_FOLLOW_LINKS', True)

return spider

def set_crawler(self, crawler):

super(CrawlSpider, self).set_crawler(crawler)

self._follow_links = crawler.settings.getbool('CRAWLSPIDER_FOLLOW_LINKS', True)

CrawlSpider 继承于 Spider 类,除了继承过来的属性外(name、allow_domains),还提供了新的属性和方法。

20.1.3 LinkExtractors

【class scrapy.linkextractors.LinkExtractor】

Link Extractors 的目的很简单: 提取链接?

每个LinkExtractor有唯一的公共方法是 extract_links(),它接收一个 Response 对象,并返回一个 scrapy.link.Link 对象。

Link Extractors 要实例化一次,并且 extract_links 方法会根据不同的 response 调用多次提取链接?

class scrapy.linkextractors.LinkExtractor(

allow = (),

deny = (),

allow_domains = (),

deny_domains = (),

deny_extensions = None,

restrict_xpaths = (),

tags = ('a','area'),

attrs = ('href'),

canonicalize = True,

unique = True,

process_value = None

)

主要参数:

【allow】:满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。

【deny】:与这个正则表达式(或正则表达式列表)不匹配的 URL 一定不提取。

【allow_domains】:会被提取的链接的 domains。

【deny_domains】:一定不会被提取链接的 domains。

【restrict_xpaths】:使用 xpath 表达式,和 allow 共同作用过滤链接。

20.1.4 rules

from scrapy.spiders import Rule

查看 Rule 方法实现的源码。

在 rules 中包含一个或多个 Rule 对象,每个 Rule 对爬取网站的动作定义了特定操作。如果多个 rule 匹配了相同的链接,则根据规则在本集合中被定义的顺序,第一个会被使用。

class scrapy.spiders.Rule(

link_extractor,

callback = None,

cb_kwargs = None,

follow = None,

process_links = None,

process_request = None

)

主要参数:

【link_extractor】:是一个 Link Extractor 对象,用于定义需要提取的链接。

【callback】: 从 link_extractor 中每获取到链接时,参数所指定的值作为回调函数,该回调函数接受一个 response 作为其第一个参数。

注意:当编写爬虫规则时,避免使用 parse 作为回调函数。由于 CrawlSpider 使用 parse方法来实现其逻辑,如果覆盖了 parse方法,crawl spider 将会运行失败。

【follow】:是一个布尔( Boolean )值,指定了根据该规则从 response 提取的链接是否需要跟进。 如果 callback 为 None,follow 默认设置为 True ,否则默认为 False。

【process_links】:指定该 spider 中哪个的函数将会被调用,从link_extractor 中获取到链接列表时将会调用该函数。该方法主要用来过滤。

【process_request】:指定该 spider 中哪个的函数将会被调用, 该规则提取到每个request 时都会调用该函数。 (用来过滤 request )

20.1.5 爬取规则( Crawling rules )

为了弄清楚爬取规则( Crawling rules )的实现过程,我们以腾讯招聘为例,使用 Scrapy Shell 交互终端一步一步展现实现的过程。

第一步:进入项目的根目录。

D:\scrapy_project\tencent\tencent

执行下列命令来调用 Scrapy Shell 交互终端,发送请求。

scrapy shell "http://hr.tencent.com/position.php?&start=0"

第二步:分析腾讯招聘网站的招聘信息的分页 URL 链接。

position.php?&start=20

position.php?&start=30

position.php?&start=40

position.php?&start=50

position.php?&start=60

每个链接组合 https://hr.tencent.com/ 就是一个完整的腾讯招聘网站的招聘信息的分页 URL 链接地址。

我们要做的就是通过正则表达式把页面里的链接(position.php?&start=20

…)提取出来。

page_lx = LinkExtractor(allow=('position.php?&start=\d+'))

第三步:获取请求响应的内容。

【response.body】

【response.text】

通常是使用 response.text 显示的是 Unicode 完整的字符串,便于匹配,一般情况,只是打印内容的时候,使用 response.body,需要解析请求的内容时,就使用:response.text

第四步:导入 LinkExtractor,创建 LinkExtractor 实例对象。

from scrapy.linkextractors import LinkExtractor

page_lx = LinkExtractor(allow=('position.php?&start=\d+'))

allow : LinkExtractor 对象最重要的参数之一,这是一个正则表达式,必须要匹配这个正则表达式(或正则表达式列表)的URL才会被提取,如果没有给出(或为空), 它会匹配所有的链接?

deny : 用法同 allow,只不过与这个正则表达式匹配的 URL 不会被提取)?它的优先级高于 allow 的参数,如果没有给出(或 None), 将不排除任何链接?

第五步:调用 LinkExtractor 实例的 extract_links() 方法查询匹配结果。

没有查到,显示为:[]

这是由于转义字符的问题引起,修改正则表达式内容,继续重新匹配:

page_lx = LinkExtractor(allow=('position\.php\?&start=\d+'))

page_lx.extract_links(response)

或者可以如下获取链接

page_lx = LinkExtractor(allow = ('start=\d+'))

page_lx.extract_links(response)

这样我们就可以获取到了所有分页的链接地址了。

20.1.6 编写Item文件

import scrapy

class TencentItem(scrapy.Item):

# define the fields for your item here like:

# 职位名

positionname = scrapy.Field()

# 详情连接

positionlink = scrapy.Field()

# 职位类别

positionType = scrapy.Field()

# 招聘人数

peopleNum = scrapy.Field()

# 工作地点

workLocation = scrapy.Field()

# 发布时间

publishTime = scrapy.Field()

20.1.7 编写爬虫文件

import scrapy,sys,os

# 导入CrawlSpider类和Rule

from scrapy.spiders import CrawlSpider, Rule

# 导入链接规则匹配类,用来提取符合规则的连接

from scrapy.linkextractors import LinkExtractor

path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

sys.path.append(path)

from dg_sun.items import SunItem

class SunSpider(CrawlSpider):

name = 'sun'

allowed_domains = ['wz.sun0769.com']

start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=0']

# 投诉分页链接的提取规则,返回的符合匹配规则的链接匹配对象的列表(这里提取的是分页的链接)

pagelink = LinkExtractor(allow=("start=\d+"))

# 投诉详情页内容链接的提取规则,返回的符合匹配规则的链接匹配对象的列表

Details = LinkExtractor(allow=r'/html/question/\d+/\d+.shtml')

#多条 Rule

rules = (

# 提取匹配,并跟进链接(没有 callback 意味着 follow 默认为 True )

Rule(pagelink),

Rule(Details, callback = 'parse_item',follow = True),

)

# 指定的回调函数

def parse_item(self, response):

item = SunItem()

#标题

item['title'] = response.xpath('//div[contains(@class, "pagecenter p3")]//strong/text()').extract()[0]

# 编号

item['id'] = item['title'].split(' ')[-1].split(":")[-1]

# 内容

item['content'] = response.xpath('//div[@class="c1 text14_2"]/text()').extract()[0]

# 链接

item['url'] = response.url

yield item注意:callback 千万不能写 parse()方法,再次强调:由于 CrawlSpider 使用 parse()方法来实现其逻辑,如果覆盖了 parse方法,crawl spider 将会运行失败。

20.1.8 编写管道文件

import json

class TencentPipeline(object):

def __init__(self):

self.filename = open("tencent.json", "wb")

def process_item(self, item, spider):

text = json.dumps(dict(item), ensure_ascii = False) + ",\n"

self.filename.write(text.encode("utf-8"))

return item

def close_spider(self, spider):

self.filename.close()

管道文件跟之前案例的写法一样,没有变化。

20.1.9 修改 settings 文件

在 settings.py 文件配置里指定刚才编写的管道文件名:TencentPipeline。

下载的数据比较多,需要设定一个下载延时时间,以免下载的数据不全。

设置爬虫请求的默认头信息。

20.1.10 运行爬虫

在 dos下切换到目录

D:\scrapy_project\tencent\tencent\ 下

通过命令运行爬虫 :scrapy crawl tencent

20.1.11查看爬取的结果

查看新建的 tencent.json 数据文件。

1.2 Logging 日志

Scrapy 提供了 log 功能,可以通过 logging 模块使用。

如果我们想把爬虫的输入日志保存到本地,需要在 settings.py 文件里进行设置。

# 保存日志信息的文件名

LOG_FILE = "tencent_log.log"

# 保存日志等级的设置,LOG_LEVEL(可选的级别有: CRITICAL、 ERROR、WARNING、INFO 、DEBUG )(从高到底)

LOG_LEVEL = " DEBUG "

设置完成之后,重新运行爬虫,结果显示如下。

【Log levels】

Scrapy 提供 5 层 logging 级别:

CRITICAL - 严重错误( critical )。

ERROR - 一般错误(regular errors )。

WARNING - 警告信息( warning messages )。

INFO - 一般信息( informational messages )。

DEBUG - 调试信息( debugging messages )。

【logging设置】

通过在 setting.py 中进行以下设置可以被用来配置 logging:

LOG_ENABLED 默认: True,启用logging

LOG_ENCODING 默认: 'utf-8',logging 使用的编码

LOG_FILE 默认: None,在当前目录里创建 logging 输出文件的文件名

LOG_LEVEL 默认: 'DEBUG',log 的最低级别

LOG_STDOUT 默认: False 如果为 True,进程所有的标准输出(及错误)将会被重定向到 log中。

相关推荐

团队管理“布阵术”:3招让你的团队战斗力爆表!

为何古代军队能够以一当十?为何现代企业有的团队高效似“特种部队”,有的却松散若“游击队”?**答案正隐匿于“布阵术”之中!**今时今日,让我们从古代兵法里萃取3个核心要义,助您塑造一支战斗力爆棚的...

知情人士回应字节大模型团队架构调整

【知情人士回应字节大模型团队架构调整】财联社2月21日电,针对原谷歌DeepMind副总裁吴永辉加入字节跳动后引发的团队调整问题,知情人士回应称:吴永辉博士主要负责AI基础研究探索工作,偏基础研究;A...

豆包大模型团队开源RLHF框架,训练吞吐量最高提升20倍

强化学习(RL)对大模型复杂推理能力提升有关键作用,但其复杂的计算流程对训练和部署也带来了巨大挑战。近日,字节跳动豆包大模型团队与香港大学联合提出HybridFlow。这是一个灵活高效的RL/RL...

创业团队如何设计股权架构及分配(创业团队如何设计股权架构及分配方案)

创业团队的股权架构设计,决定了公司在随后发展中呈现出的股权布局。如果最初的股权架构就存在先天不足,公司就很难顺利、稳定地成长起来。因此,创业之初,对股权设计应慎之又慎,避免留下巨大隐患和风险。两个人如...

消息称吴永辉入职后引发字节大模型团队架构大调整

2月21日,有消息称前谷歌大佬吴永辉加入字节跳动,并担任大模型团队Seed基础研究负责人后,引发了字节跳动大模型团队架构大调整。多名原本向朱文佳汇报的算法和技术负责人开始转向吴永辉汇报。简单来说,就是...

31页组织效能提升模型,经营管理团队搭建框架与权责定位

分享职场干货,提升能力!为职场精英打造个人知识体系,升职加薪!31页组织效能提升模型如何拿到分享的源文件:请您关注本头条号,然后私信本头条号“文米”2个字,按照操作流程,专人负责发送源文件给您。...

异形柱结构(异形柱结构技术规程)

下列关于混凝土异形柱结构设计的说法,其中何项正确?(A)混凝土异形柱框架结构可用于所有非抗震和抗震设防地区的一般居住建筑。(B)抗震设防烈度为6度时,对标准设防类(丙类)采用异形柱结构的建筑可不进行地...

职场干货:金字塔原理(金字塔原理实战篇)

金字塔原理的适用范围:金字塔原理适用于所有需要构建清晰逻辑框架的文章。第一篇:表达的逻辑。如何利用金字塔原理构建基本的金字塔结构受众(包括读者、听众、观众或学员)最容易理解的顺序:先了解主要的、抽象的...

底部剪力法(底部剪力法的基本原理)

某四层钢筋混凝土框架结构,计算简图如图1所示。抗震设防类别为丙类,抗震设防烈度为8度(0.2g),Ⅱ类场地,设计地震分组为第一组,第一自振周期T1=0.55s。一至四层的楼层侧向刚度依次为:K1=1...

结构等效重力荷载代表值(等效重力荷载系数)

某五层钢筋混凝土框架结构办公楼,房屋高度25.45m。抗震设防烈度8度,设防类别丙类,设计基本地震加速度0.2g,设计地震分组第二组,场地类别为Ⅱ类,混凝土强度等级C30。该结构平面和竖向均规则。假定...

体系结构已成昭告后世善莫大焉(体系构架是什么意思)

实践先行也理论已初步完成框架结构留余后人后世子孙俗话说前人栽树后人乘凉在夏商周大明大清民国共和前人栽树下吾之辈已完成结构体系又俗话说青出于蓝而胜于蓝各个时期任务不同吾辈探索框架结构体系经历有限肯定发展...

框架柱抗震构造要求(框架柱抗震设计)

某现浇钢筋混凝土框架-剪力墙结构高层办公楼,抗震设防烈度为8度(0.2g),场地类别为Ⅱ类,抗震等级:框架二级,剪力墙一级,混凝土强度等级:框架柱及剪力墙C50,框架梁及楼板C35,纵向钢筋及箍筋均采...

梁的刚度、挠度控制(钢梁挠度过大会引起什么原因)

某办公楼为现浇钢筋混凝土框架结构,r0=1.0,混凝土强度等级C35,纵向钢筋采用HRB400,箍筋采用HPB300。其二层(中间楼层)的局部平面图和次梁L-1的计算简图如图1~3(Z)所示,其中,K...

死要面子!有钱做大玻璃窗,却没有钱做“柱和梁”,不怕房塌吗?

活久见,有钱做2层落地大玻璃窗,却没有钱做“柱子和圈梁”,这样的农村自建房,安全吗?最近刷到个魔幻施工现场,如下图,这栋5开间的农村自建房,居然做了2个全景落地窗仔细观察,这2个落地窗还是飘窗,为了追...

不是承重墙,物业也不让拆?话说装修就一定要拆墙才行么

最近发现好多朋友装修时总想拆墙“爆改”空间,别以为只要避开承重墙就能随便砸!我家楼上邻居去年装修,拆了阳台矮墙想扩客厅,结果物业直接上门叫停。后来才知道,这种配重墙拆了会让阳台承重失衡,整栋楼都可能变...

取消回复欢迎 发表评论: