精通scrapy网络爬虫·刘硕

清华大学出版社·刘硕

为了理解scrapy开始学习阅读该书,在阅读过程中,对笔记形式纠结了很久,这次与以前的视频课程不同,学习的是电子书,而且更注重机理和理解scrapy的运行流程,这种情况重点知识是大段大段的文字描述,显然是直接在文档中标注和注释能达到最好的学习效果,但我又想要记录我的学习过程和让我以后重新翻阅时更方便,我又想做成mind格式。这些分歧导致我在两种方法中纠结了很久。最后选择了直接引用大段文字,在学习结束后不断的进行删减重整理的mind形式进行我的srapy学习计划

阅读开始于2022.8.13早8点,因为书籍是17年出版,版本较旧,学习过程中更注重理解而非运用,后续计划学习跟进最新部分

**************************************************************************************************************

在阅读前三章时坎坎坷坷的就过来了,但是在第四章到第6章时,部分内容怎么都难以理解,学习起来十分头疼,部分原因是对scrapy的不熟悉,但我觉的跟严重的问题,是我自己对爬虫的极度不熟练,和对基础知识如面向对象编程思想的生疏,自己本身时没有系统的学习过的,导致我去看这书非常的痛苦

因此我觉得分布解决问题,一步一步埋坑,下阶段的首先目标是先对爬虫技能的训练,当先运用熟练的运用好爬虫技能后,再将目标设为对scrapy的深入学习

所以开始学习熟练运用requests

在学习过程中学到的新知识会更新到之前的文档中

 

精通Scrapy网络爬虫

第一章 初识Scrapy

一个网络爬虫程序的基本执行流程可以总结为以下循环:

1.下载页面一个网页的内容本质上就是一个HTML文本,爬取一个网页内容之前,首先要根据网页的URL下载网页。

2.提取页面中的数据当一个网页(HTML)下载完成后,对页面中的内容进行分析,并提取出我们感兴趣的数据,提取到的数据可以以多种形式保存起来,比如将数据以某种格式(CSV、JSON)写入文件中,或存储到数据库(MySQL、MongoDB)中。

3.提取页面中的链接通常,我们想要获取的数据并不只在一个页面中,而是分布在多个页面中,这些页面彼此联系,一个页面中可能包含一个或多个到其他页面的链接,提取完当前页面中的数据后,还要把页面中的某些链接也提取出来,然后对链接页面进行爬取(循环1-3步骤)。

爬虫的实现做简单说明

name属性 一个Scrapy项目中可能有多个爬虫,每个爬虫的name属性是其自身的唯一标识,在一个项目中不能有同名的爬虫,本例中的爬虫取名为’books'。

start_urls属性 一个爬虫总要从某个(或某些)页面开始爬取,我们称这样的页面为起始爬取点,start_urls属性用来设置一个爬虫的起始爬取点。

parse方法 当一个页面下载完成后,Scrapy引擎会回调一个我们指定的页面解析函数(默认为parse方法)解析页面。一个页面解析函数通常需要完成以下两个任务: ➢ 提取页面中的数据(使用XPath或CSS选择器)。 ➢ 提取页面中的链接,并产生对链接页面的下载请求

第二章 编写Spiser

Scrapy框架结构及工作原理

scrapy爬虫框架

首先spider(爬虫)根据自身内容请求第一个要爬取的url,通过engine将url存入scheduler,由scheduler进行调控url的出列顺序,出列后经过engine向dowmloader请求下载,downloader从网络上下载内容经engine提交至spider,由spider(爬虫)进行数据处理,处理结束后提交至engine向piprline输出,这期间如果还需进行url爬取,再将url交至scheduler放入队列

框架中的数据流

request Scrapy中的HTTP请求对象

response Scrapy中的HTTP响应对象

item 从页面爬取的一项数据

理解了框架中的数据流,也就理解了Scrapy爬虫的工作原理。如果把框架中的组件比作人体的各个器官,Request和Response对象便是血液,Item则是代谢产物。

Request对象和Response对象

Request对象详解

Request对象用来描述一个HTTP请求,下面是其构造器方法的参数列表:        Request(url[, callback, method='GET', headers, body, cookies, meta,                      encoding='utf-8', priority=0, dont_filter=False, errback])

● url (必选)请求页面的url地址,bytes或str类型,如’http://www.python.org/doc'。 ● callback 页面解析函数,Callable类型,Request对象请求的页面下载完成后,由该参数指定的页面解析函数被调用。如果未传递该参数,默认调用Spider的parse方法。 ● methodHTTP 请求的方法,默认为’GET'。 ● headersHTTP 请求的头部字典,dict类型,例如{'Accept': 'text/html', 'User-Agent':Mozilla/5.0'}。如果其中某项的值为None,就表示不发送该项HTTP头部,例如{'Cookie': None},禁止发送Cookie。 ● bodyHTTP 请求的正文,bytes或str类型。 ● cookiesCookie 信息字典,dict类型,例如{'currency': 'USD', 'country': 'UY'}。 ● metaRequest 的元数据字典,dict类型,用于给框架中其他组件传递信息,比如中间件ItemPipeline。其他组件可以使用Request对象的meta属性访问该元数据字典(request.meta),也用于给响应处理函数传递信息,详见Response的meta属性。 ● encodingurl和body参数的编码默认为’utf-8'。如果传入的url或body参数是str类型,就使用该参数进行编码。 ● priority 请求的优先级默认值为0,优先级高的请求优先下载。 ● dont_filter 默认情况下(dont_filter=False),对同一个url地址多次提交下载请求,后面的请求会被去重过滤器过滤(避免重复下载)。如果将该参数置为True,可以使请求避免被过滤,强制下载。例如,在多次爬取一个内容随时间而变化的页面时(每次使用相同的url),可以将该参数置为True。 ● errback 请求出现异常或者出现HTTP错误时(如404页面不存在)的回调函数。 虽然参数很多,但除了url参数外,其他都带有默认值。

在构造Request对象时,通常我们只需传递一个url参数或再加一个callback参数,其他使用默认值即可,代码如下:        >>> import scrapy       >>> request = scrapy.Request('http://books.toscrape.com/')       >>> request2 = scrapy.Request('http://quotes.toscrape.com/', callback=self.parseItem)

Response对象详解

Response对象用来描述一个HTTP响应,Response只是一个基类,根据响应内容的不同有如下子类: ● TextResponse● HtmlResponse● XmlResponse

当一个页面下载完成时,下载器依据HTTP响应头部中的Content-Type信息创建某个Response的子类对象。我们通常爬取的网页,其内容是HTML文本,创建的便是HtmlResponse对象,其中HtmlResponse和XmlResponse是TextResponse的子类。实际上,这3个子类只有细微的差别,这里以HtmlResponse为例进行讲解。

HtmlResponse对象的属性及方法。 ● url HTTP响应的url地址,str类型。 ● status HTTP响应的状态码,int类型,例如200, 404。 ● headers HTTP响应的头部,类字典类型,可以调用get或getlist方法对其进行访问,例如:   response.headers.get('Content-Type')   response.headers.getlist('Set-Cookie') ● body HTTP响应正文,bytes类型。 ● text 文本形式的HTTP响应正文,str类型,它是由response.body使用response.encoding解码得到的,即    reponse.text = response.body.decode(response.encoding) ● encoding HTTP响应正文的编码,它的值可能是从HTTP响应头部或正文中解析出来的。 ● request 产生该HTTP响应的Request对象。 ● meta 即response.request.meta,在构造Request对象时,可将要传递给响应处理函数的信息通过meta参数传入;响应处理函数处理响应时,通过response.meta将信息取出。 ● selector Selector对象用于在Response中提取数据(选择器相关话题在后面章节详细讲解)。 ● xpath(query) 使用XPath选择器在Response中提取数据,实际上它是response.selector.xpath方法的快捷方式(选择器相关话题在后面章节详细讲解)。 ● css (query)使用CSS选择器在Response中提取数据,实际上它是response.selector.css方法的快捷方式(选择器相关话题在后面章节详细讲解)。 ● urljoin(url)用于构造绝对url。当传入的url参数是一个相对地址时,根据response.url计算出相应的绝对url。例如,response.url为http://www.example.com/a, url为b/index.html,调用response.urljoin(url)的结果为http://www.example.com/a/b/index.html。

虽然HtmlResponse对象有很多属性,但最常用的是以下的3个方法: ● xpath(query) ● css(query) ● urljoin(url) 前两个方法用于提取数据,后一个方法用于构造绝对url。

Scrapy开发流程

Scrapy框架提供了一个Spider基类,我们编写的Spider需要继承它:        import scrapy        class BooksSpider(scrapy.Spider): 

设定起爬点

Spider必然要从某个或某些页面开始爬取,我们称这些页面为起始爬取点,可以通过类属性start_urls来设定起始爬取点:  start_urls = ['http://books.toscrape.com/'] start_urls通常被实现成一个列表,其中放入所有起始爬取点的url

起爬点方法一

而我们仅定义了url列表,是谁暗中构造并提交了相应的Request对象呢?

通过阅读Spider基类的源码可以找到答案,相关代码如下:        class Spider(object_ref):         ...         def start_requests(self):   for url in self.start_urls:       yield self.make_requests_from_url(url)         def make_requests_from_url(self, url):   return Request(url, dont_filter=True)          def parse(self, response):   raise NotImplementedError          ...

● 实际上,对于起始爬取点的下载请求是由Scrapy引擎调用Spider对象的start_requests方法提交的,由于BooksSpider类没有实现start_requests方法,因此引擎会调用Spider基类的start_requests方法。 ● 在start_requests方法中,self.start_urls便是我们定义的起始爬取点列表(通过实例访问类属性),对其进行迭代,用迭代出的每个url作为参数调用make_requests_from_url方法。 ● 在make_requests_from_url方法中,我们找到了真正构造Reqeust对象的代码,仅使用url和dont_filter参数构造Request对象。 ● 由于构造Request对象时并没有传递callback参数来指定页面解析函数,因此默认将parse方法作为页面解析函数。此时BooksSpider必须实现parse方法,否则就会调用Spider基类的parse方法,从而抛出NotImplementedError异常(可以看作基类定义了一个抽象接口)。 ● 起始爬取点可能有多个,start_requests方法需要返回一个可迭代对象(列表、生成器等),其中每一个元素是一个Request对象。这里,start_requests方法被实现成一个生成器函数(生成器对象是可迭代的),每次由yield语句返回一个Request对象。

stert_urls与start_requests的具体关系

由于起始爬取点的下载请求是由引擎调用Spider对象的start_requests方法产生的,因此我们也可以在BooksSpider中实现start_requests方法(覆盖基类Spider的start_requests方法),直接构造并提交起始爬取点的Request对象。在某些场景下使用这种方式更加灵活,例如有时想为Request添加特定的HTTP请求头部,或想为Request指定特定的页面解析函数。 def start_requests(self):   yield scrapy.Request('http://books.toscrape.com/',callback=self.parse_book,                              headers={'User-Agent': 'Mozilla/5.0'},                              dont_filter=True)         # 改用parse_book作为回调函数         def parse_book(response):            ...

起爬点方法二

页面解析后讲

第三章 使用Selector

Selector对象

从页面中提取数据的核心技术是HTTP文本解析,Scrapy综合BeautifulSoup和lxml优点实现了Selector类,它是基于lxml库构建的,并简化了API接口。在Scrapy中使用Selector对象提取页面中的数据,使用时先通过XPath或CSS选择器选中页面中要提取的数据,然后进行提取。

Selector对象创建

1. 可将页面的HTML文档字符串传递给Selector构造器方法的text参数 selector = Selector(text=html)

2. 也可以使用一个Response对象构造Selector对象,将其传递给Selector构造器方法的response参数: response=HtmlResponse(url='url',body=html,ebcoding='utf-8') selsetor=Selector(response=response)

选中数据

xpath

/ 根目录 //所有下级目录 . 当前目录 .. 上一级目录 * 通配符 /name 在当前目录索引name名字的标签 ./text() 标签的文本子节点 @class 选取对应属性内容 [@class[=“ ”]]选取具有对应属性的标签

多[]或者同[]中用and连接

*可以表示任意单一节点

返回列表

例 a.xpath('//div[@class="song"]/p[3]') 返回a中具有class="song"属性的div标签下的所有p标签中第三个标签的单个列表

注意返回的是列表,且注意数字

例 a.xpath('//div[@class="tang"]//li[5]/p/text()')[0] 返回a中具有class="tang"属性的div标签下的第五个li标签下的p标签的text部分的列表的第0号元素

例 a.xpath('//div[@class="song"]/img/@src') 返回a标签下的具有class="song"属性的div标签下的img标签的src属性内容的列表

//text() 得到所有文本内容组成的列表 .xpath('string(/html/body/a)').extract() 输出a下所有的文本组成的(一整个字符串)的列表

string标签内所有的文本组合输出

contains(str1,str2)判断str1中是否包含str2 用法 .xpath('//p[contains(@class,'samll')]) 返回class中含samll的p标签的列表

包含选择

css

css('name[,name2]')选中name[和name2]标签 css('name1 name2')选中name1后代所有的name2 css('name1>name2')选中name1子代中的所有name2 css('name1+name2')选中name1同代中的所有name2 css('[calss]')选中含class属性的标签 css('[class=1]')选中class属性值为1的标签 css('[class=~1]')选中class属性值包含1的标签 css('name.1')输出属性值中含1的标签 css('name#1')输出属性值中为1的标签 css('div>a:nth-child(n)')选中div下第n个a标签          nth可以换为first或last选择第一个或最后一个 css('div>a:nth-last-child(n)')选中div下倒数第n个a标签 css('a::text')输出文本部分 css('a::attr(class))输出calss属性的值 css(a:empty)选择没有子元素的a标签

多[]或者同[]中用and连接

调用Selector对象的xpath方法或css方法(传入XPath或CSS选择器表达式),可以选中文档中的某个或某些部分: SelectorList对象也有xpath和css方法,调用它们的行为是:以接收到的参数分别调用其中每一个Selector对象的xpath或css方法,并将所有结果收集到一个新的SelectorList对象返回给用户。

Selectorlist对象多个Selectorlist对象包含原选择器参数和选择内容 >>> sl = selector.xpath('.//li')       >>> sl        [<Selector xpath='.//li' data='<li>C++</li>'>,        <Selector xpath='.//li' data='<li>Java</li>'>,         <Selector xpath='.//li' data='<li>Python</li>'>]

提取数据

调用Selector或SelectorLis对象的以下方法可将选中的内容提取: ● extract() ● re() ● extract_first() (SelectorList专有) ● re_first() (SelectorList专有)

extract与extract_first 调用Selector对象的extract方法将返回其选中内容:               >>> sl.xpath('./text').extract() ['C++',Java','Python'] >>>sl.xpath('./text()').extract_first() 'C++'

re()与re.first()                       >>> selector.xpath('.//li/b/text()')       [<Selector xpath='.//li/b/text()' data=’价格: 99.00元’>,        <Selector xpath='.//li/b/text()' data=’价格: 88.00元’>,        <Selector xpath='.//li/b/text()' data=’价格: 80.00元’>]               >>> selector.xpath('.//li/b/text()').re('\d+\.\d+')        ['99.00', '88.00', '80.00'] >>> selector.xpath('.//li/b/text()').re_first('\d+\.\d+') '99.00'

一般response对象内置selector对象一般直接引用即可

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Murle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值