组件 | 描述 | 类型 |
---|---|---|
Scrapy Engine | 引擎,负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等 | 内部组件 |
Scheduler | 调度器:,它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。 | 内部组件 |
Downloader | 下载器:负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理 | 内部组件 |
Spider | 爬虫:它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器), | 用户实现 |
Item Pipeline | 管道:它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方. | 可选组件 |
Downloader Middlewares | 下载中间件:你可以当作是一个可以自定义扩展下载功能的组件,负责对resquest和response对象处理。 | 可选组件 |
Spider Middlewares | Spider中间件:你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests ) | 可选组件 |
流程:
Request对象用来描述一个HTTP请求,下面是其构造器方法的参数列表:
Request(url[,callback,method='GET',headers,body,cookies,meta,encoding='utf8',priority=0,dont_filter=False,errback])
参数 | 描述 |
---|---|
url(必须) | 请求页面的url地址,bytes或str类型, 如’http://www.python.org/doc’。 |
callback | 页面解析函数,Callable类型,Request对象请求的页面下载完成后,由该参数指定的页面解析函数被调用。如果未传递该参数,默认调用Spider的parse方法 |
method | HTTP请求的方法,默认为’GET’ |
headers | HTTP请求的头部字典,dict类型,例如{‘Accept’: ‘text/html’,‘User-Agent’:Mozilla/5.0’}。如果其中某项的值为None,就表示不发送该项HTTP头部,例如{‘Cookie’: None},禁止发送Cookie |
body | HTTP请求的正文,bytes或str类型 |
cookies | Cookie信息字典,dict类型,例如{‘currency’:‘USD’, ‘country’:‘UY’}。 |
meta | Request的元数据字典,dict类型,用于给框架中其他组件传递信息,比如中间件Item Pipeline。其他组件可以使用Request对象的meta属性访问该元数据字典(request.meta),也用于给响应处理函数传递信息,详见Response的meta属性 |
encoding | url和body参数的编码默认为’utf-8’。如果传入的url或 body参数是str类型,就使用该参数进行编码。 |
priority | 请求的优先级默认值为0,优先级高的请求优先下载。 |
dont_filter | 默认情况下(dont_filter=False),对同一个url地址多次提交下载请求,后面的请求会被去重过滤器过滤(避免重复下载)。如果将该参数置为True,可以使请求避免被过滤,强制下载。例如,在多次爬取一个内容随时间而变化的页面时(每次使用相同的url),可以将该参数置为True。 |
errback | 请求出现异常或者出现HTTP错误时(如404页面不存在)的回调函数。 |
Response对象用来描述一个HTTP响应,Response只是一个基类,根据响应内容的不同有TextResponse,HtmlResponse,XmlResponse,我们通常爬取的网页,其内容是HTML文本,创建的便是HtmlResponse对象,HtmlResponse对象有很多属性,但最常用的是以下的3个方法:
Scrapy框架提出以下问题让用户在Spider子类中作答:
● 爬虫从哪个或哪些页面开始爬取?
● 对于一个已下载的页面,提取其中的哪些数据?
● 爬取完当前页面后,接下来爬取哪个或哪些页面?
上面问题的答案包含了一个爬虫最重要的逻辑,回答了这些问题,一个爬虫也就开发出来了。
以上一节的代码为例:
import scrapy
class BooksSpider(scrapy.Spider):
# 定义唯一标识
name = "books"
# 爬虫爬取起点网页
start_urls = [
'http://books.toscrape.com/',
]
def parse(self, response):
# 提取数据
# 每一本书的信息在中
# css()方法找到所有这样的article元素,并依次迭代
for book in response.css('article.product_pod'):
# 选择器可以通过命令行工具就行调试
# 书名信息在article>h3>a元素的title属性里
# 例 如:A Light in the...
# 书价信息在的TEXT中。
# 例如:£51.77
yield {
# xpath 语法 @ATTR 为选中为名ATTR的属性节点
'name': book.xpath('h3/a/@title').get(),
'price': book.css('p.price_color::text').get(),
}
# 检查分页
# 提取下一页的链接
#例如:next
next_url = response.css('ul.pager li.next a::attr(href)').extract_first()
if next_url:
next_url = response.urljoin(next_url)
# 构造新的 Request 对象
yield scrapy.Request(next_url, callback=self.parse)
实现一个爬虫的主要步骤有4个。
import scrapy
class BooksSpider(scrapy.Spider):
...
name = "books"
一个scrapy项目中可以有多个Spider,类属性name就是每一个Spider的唯一标识。在scrapy crawl命令中就使用了该标志,表示启动哪一个Spider。
start_urls = ['http://books.toscrape.com/',]
这是一个列表,可以放置所有起始网页。scrapy会调用Spider的start_requests方法,实现对起始网页的下载请求。我们也可以重构该方法。
def start_requests(self):
yield scrapy.Request('http://books.toscrape.com/',
callback=self.parse_book,
headers={'UserAgent': 'Mozilla/5.0'},
dont_filter=True)
页面解析函数也就是构造Request对象时通过callback参数指定的回调函数(或默认的parse方法)。页面解析函数是实现Spider中最核心的部分,它需要完成以下两项工作:
● 使用选择器提取页面中的数据,将数据封装后(Item或字典) 提交给Scrapy引擎。
● 使用选择器或LinkExtractor提取页面中的链接,用其构造新的 Request对象并提交给Scrapy引擎(下载链接页面)。
一个页面中可能包含多项数据以及多个链接,因此页面解析函数被要求返回一个可迭代对象(通常被实现成一个生成器函数),每次迭代返回一项数据(Item或字典)或一个Request对象。
需求很简单,抓取博客的链接。起始界面为https://blog.csdn.net/fxflyflyfly
import scrapy
class BooksSpider(scrapy.Spider):
name = "csdn"
start_urls = ['https://blog.csdn.net/fxflyflyfly/article/list/1?',
'https://blog.csdn.net/fxflyflyfly/article/list/2?']
def parse(self, response):
for book in response.css('div.article-item-box'):
yield {
'name':book.xpath('//a/text()').get(),
'type':book.css('span.article-type::text').get(),
'list':book.css('h4 a::attr(href)').get(),
}
因为目前的博客数量不多,不用分页处理,直接设置两个起始网页,抓取博客标题,类型和url。运行上述代码,并将数据保存(出现了中文乱码的问题,暂时还没有解决)。之后处理
接下来就是利用这些链接刷博客量。
import webbrowser as web
import os
import time
url = []
with open('C:/Users/fx/example/example/spiders/csdn.csv', encoding='utf-8') as lines:
next(lines)
for line in lines:
url.append(line.split(',')[-1].strip())
for j in range(10):
for i in url:
web.open(i, 0, autoraise=False)
time.sleep(2)
os.system('taskkill /F /IM MicrosoftEdgeCP.exe')
time.sleep(30)
上述通过打开电脑默认浏览器浏览指定url,通过直接杀死进程的方式关闭网页。