python 入门

大师兄的Python学习笔记(三十): 爬虫(十一)

2020-09-16  本文已影响0人  superkmi

大师兄的Python学习笔记(二十九): 爬虫(十)
大师兄的Python学习笔记(三十一): 爬虫(十二)

十一、Scrapy框架

6. 关于Selector
6.1 使用方法

1) xpath选择器

  • xpath选择器使用selector.xpath()
  • 在xpath选择器中添加/text()选取文本内容。
  • 在xpath选择器中添加/@(<name>)选取属性。
>>>from scrapy import Selector

>>>html = '''
>>>    <html>
>>>        <head>
>>>            <title>
>>>                hello
>>>            </title>
>>>        </head>
>>>    </html>'''
>>>selector = Selector(text=html)
>>>title = selector.xpath('//title/text()').extract()
>>>print(title)
['\n                hello\n            ']

2) css选择器

  • css选择器使用selector.css()
  • 在选择器中添加::text选取文本内容。
  • 在选择器中添加::attr(<name>)选取某个属性。
>>>from scrapy import Selector

>>>html = '''
>>>    <html>
>>>        <head>
>>>            <title>
>>>                hello
>>>            </title>
>>>        </head>
>>>    </html>'''
>>>selector = Selector(text=html)
>>>title = selector.css('title::text').extract()
>>>print(title)
['\n                hello\n            ']

3) 正则匹配

  • 正则使用selector.re()匹配所有内容,或使用selector.re_first()匹配第一个内容。
>>>from scrapy import Selector

>>>html = '''
>>>    <html>
>>>        <head>
>>>            <title>
>>>                hello
>>>            </title>
>>>        </head>
>>>    </html>'''
>>>selector = Selector(text=html)
>>>title = selector.re('h.*o')
>>>print(title)
['hello']
  • 正则匹配还可以和选择器搭配使用
>>>from scrapy import Selector

>>>html = '''
>>>    <html>
>>>        <head>
>>>            <title>
>>>                hello
>>>            </title>
>>>        </head>
>>>    </html>'''
>>>selector = Selector(text=html)
>>>title = selector.css('title::text').re('e.*o')
>>>print(title)
['ello']
7. 关于Spider
7.1 爬虫的爬取流程

1) 以初始URL初始化Request,并设置回调函数parse(self, response)。请求成功后将response做为参数传给回调函数。

2) 在回调函数中分析网页内容,内容分两类:

  • 如果是有效结果,则返回Item或字典。
  • 如果是下一页,则用新的URL构造request并设置新的回调函数。

2-1) 如果返回结果,可通过Feed Exports等组件将返回结果存入文件,如果设置了Pipeline,则使用Pipeline处理并保存。

2-2) 如果返回下一页的请求,则根据请求结果并执行相应的回调函数, 解析并生成Item。
重复以上步骤,直到完成爬取。

7.2 scrapy.spiders.Spider类
属性 介绍
name 爬虫的名称。
allowed_domains 允许爬取的域名白名单,可选。
start_urls 默认起始url列表,在没有实现start_requests()方法时从这里默认爬取。
custom_settings 爬虫的配置字典,会覆盖全局设置。
crawler 爬虫对应的Crawler对象,可以用来获取项目的配置信息settings
settings Settings对象,可以直接获取项目的全局设置变量。
方法 介绍
start_requests() 用于生成初始请求,默认使用start_urls里的URL构造请求,并返回一个可迭代对象。
parse() Response没有指定回调函数时被默认调用。
负责处理返回结果,并从中提取数据和下一步请求。
返回一个包含RequestItem的可迭代对象。
closed() 当爬虫被关闭时调用。
8. 关于Downloader Middleware

1) 请求发送给下载器之前。

  • Scheduler -> Engine -> Downloader Middlewares-> Downloader

2) 响应发送给引擎->爬虫之前。

  • Downloader ->Downloader Middlewares-> Engine -> Spider
8.1 核心方法

1) process_request(request,spider)

  • 在请求发送给下载器之前调用。
  • 参数:
参数 说明
request 被处理的Request对象
spider 对应的爬虫对象
  • 返回值必须是None、Response对象、Request对象之一, 或抛出IgnoreRequest异常:
返回值 说明
None - 继续执行其他process_request()方法,直到下载器获得Response。
- 本质是根据优先级修改Request。
- 最后发送给Downloader执行。
Response对象 - 更低优先级的process_request()方法和process_exception()方法不会被继续调用。
- 每个process_response()方法转而被依次调用。
- 完成后将Response发送给爬虫处理。
Request对象 - 更低优先级的process_request()方法会停止执行。
- 这个Request会作为一个全新的Request放到调度队列里,等待调度。
- 被调度后,process_request()会被重新按照顺序执行。
抛出IgnoreRequest异常 - 所有的process_exception()方法依次执行。
如果异常没有被处理,则使用Request的errorback()方法回调。
如果异常还没有被处理,则忽略。

2) process_response(request,response,spider)

  • 在相应发送给爬虫之前调用。
  • 参数:
参数 说明
request Response对应的Request对象。
response 等待被处理的Response对象。
spider 对应的爬虫对象。
  • 返回值必须是Request对象、Response对象之一,或抛出IgnoreRequest异常。
返回值 说明
Request对象 - 更低优先级的process_response()方法不会继续调用。
- 这个Request会作为一个全新的Request放到调度队列里,等待调度。
- 被调度后,process_request()会被按照顺序执行。
Response对象 - 更低优先级的process_response()方法会继续调用,对该Response对象进行处理。
抛出IgnoreRequest异常 - Request的errorback()方法回调。
- 如果异常还没有被处理,则忽略。

3) process_exception(request,exception,spider)

  • 当下载器或process_request()方法抛出异常时被调用。
  • 参数:
参数 说明
request 产生异常的Request对象。
exception 被抛出的Exception对象。
spider 对应的爬虫对象。
  • 返回值必须是None、Response对象、Request对象之一。
参数 说明
None - 更低优先级的process_exception()会被继续按顺序调用,直到所有方法都被调度完毕。
Response对象 - 更低优先级的process_exception()不再被继续调用。
- process_response()方法装而被依次调用。
Request对象 - 更低优先级的process_exception()不再被继续调用。
- 这个Request会作为一个全新的Request放到调度队列里,等待调度。
- 被调度后,process_request()会被按照顺序执行。
>>>DOWNLOADER_MIDDLEWARES = {
>>>   'project_sample.middlewares.ProjectSampleDownloaderMiddleware': 543,
>>>}
>>>class ProjectSampleDownloaderMiddleware(object):
>>>    def __init__(self,user_agent):
>>>        self.user_agent=user_agent

>>>    @classmethod
>>>    def from_crawler(cls, crawler):
>>>        s = cls(crawler.settings['USER_AGENT'])
>>>        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
>>>        return s

>>>    def process_request(self, request, spider):
>>>        if self.user_agent:
>>>            request.headers.setdefault(b'User-Agent',self.user_agent)
>>>        return None

>>>    def spider_opened(self, spider):
>>>        self.user_agent = getattr(spider,'user_agent',self.user_agent)
9. 关于Spider Middleware

1) 下载器将生成的响应发送给爬虫之前

  • Downloader -> Engine -> Spider Middlewares -> Spiders

2) 爬虫将请求发送给Scheduler之前

  • Spider -> Spider Middlewares ->Engine -> Scheduler

3) 爬虫将生成的项目发给Item Pipeline之前
Spider -> Spider Middlewares ->Engine -> Item Pipeline

9.1 核心方法

1) process_spider_input(response,spider)

  • 当爬虫中间件处理response时,该方法会被调用。
  • 参数:
参数 说明
response 将被处理的Response对象。
spider 对应的爬虫对象。
  • 返回值应该是None或者抛出异常:
返回值 说明
None 调用其它中间件,直到Spider处理这个Response。
抛出异常 - 不会调用其它的爬虫中间件,而是调用errback()方法。
- errback()的输出使用process_spider_output()方法处理。
- 异常调用process_spider_exception()处理。

2) process_spider_output(response,result,spider)

  • 当爬虫处理Response返回结果时调用。
  • 参数:
参数 说明
response 将被处理的Response对象。
result 爬虫的返回结果,包含Request或Item的可迭代对象。
spider 对应的爬虫对象。
  • 返回值是处理过的result,必须包含Request或item的可迭代对象。

3) process_spider_exception(response,exception,spider)

  • process_spider_input()抛出异常时调用。
  • 参数:
参数 说明
response 将被处理的Response对象。
exception 被抛出的Exception对象。
spider 对应的爬虫对象。
  • 返回值应该是None或者包含Response/Item的可迭代对象:
返回值 说明
None 继续调用其它process_spider_exception()方法,直到全部被调用。
Response/Item可迭代对象 调用process_spider_output()方法。

4) process_start_requests(start_requests,spider)

  • 当爬虫发起参数时被调用。
参数 说明
start_requests 包含Request的可迭代对象
spider 对应的爬虫对象。
  • 返回处理过的start_requests,也就是包含Request的可迭代对象。
>>>SPIDER_MIDDLEWARES = {
>>>>   'project_sample.middlewares.ProjectSampleSpiderMiddleware': 543,
>>>}
class ProjectSampleSpiderMiddleware(object):
    def process_spider_output(self, response, result, spider):
        for i in result:
            if isinstance(i, scrapy.Item):
                print('现在将把Item发送到pipeline')
            yield i
... ...
现在将把Item发送到pipeline
2020-09-15 11:12:22 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/26357307/>
{'actors': 27,
 'director': '妮琪·卡罗',
 'title': '花木兰 Mulan',
 'url': 'https://movie.douban.com/subject/26357307/'}
... ...
10. 关于Item Pipeline

1) 清理HTML数据。
2) 验证爬取数据,检查爬取字段。
3) 查重并丢弃重复内容。
4) 将爬取结果保存到数据库。

10.1 使用Item Pipeline

1) process_item(item,spider)

  • 定义后的Item Pipeline会默认调用此方法。
  • 参数:
参数 说明
item 爬虫生成的Item对象。
spider 对应的爬虫。
  • 可以返回Item对象或抛出DropItem异常:
返回值 说明
Item对象 所有Item Pipeline按优先级继续处理。
抛出DropItem异常 Item对象被丢弃,不在进行处理。

2) open_spider(spider)

  • 在爬虫开启时被自动调用, 通常用来执行初始化工作。
  • 参数spider是相应的爬虫对象。

3) close_spider(spider)

  • 在爬虫关闭时被自动调用, 通常用来执行收尾工作。
  • 参数spider是相应的爬虫对象。

4) from_crawler(cls,crawler)

  • from_crawler()是类方法, 用@classmethod标识。
  • 类方法的第一个参数(cls)必须是类的实例。
  • 参数crawler是crawler对象,可以用于获得scrapy的全局配置信息。
>>>from scrapy.exceptions import DropItem

>>>class ProjectSamplePipeline(object):
>>>    def process_item(self, item, spider):
>>>        # 将演员名称替换为演员数量
>>>        if item.get('actors'):
>>>            item['actors'] = len(item['actors'])
>>>            return item
>>>        else:
>>>            return DropItem("No actors")
>>># Configure item pipelines
>>># See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
>>>ITEM_PIPELINES = {
>>>   'project_sample.pipelines.ProjectSamplePipeline': 300,
>>>}
D:\project_sample>scrapy crawl douban
... ...
{'actors': 18,
 'director': '泰特·泰勒',
 'title': '艾娃 Ava',
 'url': 'https://movie.douban.com/subject/30289869/'}
2020-09-10 09:56:46 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://movie.douban.com/subject/30129061/> (referer: https://movie.douban.com/chart)
2020-09-10 09:56:46 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://movie.douban.com/subject/27131969/> (referer: https://movie.douban.com/chart)
2020-09-10 09:56:46 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://movie.douban.com/subject/34462775/> (referer: https://movie.douban.com/chart)
2020-09-10 09:56:46 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/35141706/>
{'actors': 10,
 'director': '周润泽',
 'title': '东北往事:我叫刘海柱',
 'url': 'https://movie.douban.com/subject/35141706/'}
2020-09-10 09:56:46 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/30330875/>
{'actors': 27,
 'director': '亨利·朱斯特',
 'title': '超能计划 Project Power',
 'url': 'https://movie.douban.com/subject/30330875/'}
2020-09-10 09:56:47 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/30479644/>
{'actors': 27,
 'director': '杨宇硕',
 'title': '铁雨2:首脑峰会 강철비2: 정상회담',
 'url': 'https://movie.douban.com/subject/30479644/'}
2020-09-10 09:56:47 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/26389321/>
{'actors': 14,
 'director': '约什·布恩',
 'title': '新变种人 The New Mutants',
 'url': 'https://movie.douban.com/subject/26389321/'}
2020-09-10 09:56:47 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/30129061/>
{'actors': 15,
 'director': '查理·考夫曼',
 'title': "我想结束这一切 I'm Thinking of Ending Things",
 'url': 'https://movie.douban.com/subject/30129061/'}
2020-09-10 09:56:47 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/27131969/>
{'actors': 6,
 'director': '李云波',
 'title': '无名狂',
 'url': 'https://movie.douban.com/subject/27131969/'}
2020-09-10 09:56:47 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/34462775/>
{'actors': 2,
 'director': '赵一亨',
 'title': '#活着 #살아있다',
 'url': 'https://movie.douban.com/subject/34462775/'}
2020-09-10 09:56:47 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://movie.douban.com/subject/26357307/> (referer: https://movie.douban.com/chart)
2020-09-10 09:56:47 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://movie.douban.com/subject/30299515/> (referer: https://movie.douban.com/chart)
2020-09-10 09:56:47 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/26357307/>
{'actors': 27,
 'director': '妮琪·卡罗',
 'title': '花木兰 Mulan',
 'url': 'https://movie.douban.com/subject/26357307/'}
2020-09-10 09:56:47 [scrapy.core.scraper] DEBUG: Scraped from <200 https://movie.douban.com/subject/30299515/>
{'actors': 8,
 'director': '延尚昊',
 'title': '釜山行2:半岛 부산행2-반도',
 'url': 'https://movie.douban.com/subject/30299515/'}
... ...
10.2 将数据保存到数据库
>>># Configure item pipelines
>>># See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
>>>ITEM_PIPELINES = {
>>>   'project_sample.pipelines.ProjectSamplePipeline': 300,
>>>   'project_sample.pipelines.MongoDBPipeline': 400,
>>>}
>>>MONGO_URI='localhost'
>>>MONGO_DB='project'
>>>import pymongo

>>>class MongoDBPipeline(object):
>>>    def __init__(self,mongo_uri,mongo_db):
>>>        self.mongo_uri = mongo_uri
>>>        self.mongo_db = mongo_db

>>>    @classmethod
>>>    def from_crawler(cls,crawler):
>>>        # 类方法,用于获取settings中的全局的配置信息
>>>        return cls(
>>>            mongo_uri=crawler.settings.get('MONGO_URI'),
>>>            mongo_db=crawler.settings.get('MONGO_DB')
>>>        )

>>>    def open_spider(self,spider):
>>>        '''
>>>        spider开启时调用
>>>        用于初始化mongodb
>>>        '''
>>>        self.client = pymongo.MongoClient(self.mongo_uri)
>>>        self.db = self.client[self.mongo_db]

>>>    def close_spider(self,spider):
>>>        '''
>>>        spider结束时调用
>>>        用于关闭数据库链接
>>>        '''
>>>        self.client.close()

>>>    def process_item(self, item, spider):
>>>        name = item.__class__.__name__
>>>        self.db[name].insert(dict(item))
>>>        return item
> db.ProjectSampleItem.find()
{ "_id" : ObjectId("5f59929c69d6a3f8e7263087"), "url" : "https://movie.douban.com/subject/35141706/", "title" : "东北往事:我叫刘海柱", "actors" : 10, "director" : "周润泽" }
{ "_id" : ObjectId("5f59929c69d6a3f8e7263088"), "url" : "https://movie.douban.com/subject/34462775/", "title" : "#活着 #살아있다", "actors" : 2, "director" : "赵一亨" }
{ "_id" : ObjectId("5f59929c69d6a3f8e7263089"), "url" : "https://movie.douban.com/subject/30289869/", "title" : "艾娃 Ava", "actors" : 18, "director" : "泰特·泰勒" }
{ "_id" : ObjectId("5f59929c69d6a3f8e726308a"), "url" : "https://movie.douban.com/subject/26389321/", "title" : "新变种人 The New Mutants", "actors" : 14, "director" : "约什·布恩" }
{ "_id" : ObjectId("5f59929c69d6a3f8e726308b"), "url" : "https://movie.douban.com/subject/30330875/", "title" : "超能计划 Project Power", "actors" : 27, "director" : "亨利·朱斯特" }
{ "_id" : ObjectId("5f59929c69d6a3f8e726308c"), "url" : "https://movie.douban.com/subject/30479644/", "title" : "铁雨2:首脑峰会 강철비2: 정상회담", "actors" : 27, "director" : "杨宇硕" }
{ "_id" : ObjectId("5f59929c69d6a3f8e726308d"), "url" : "https://movie.douban.com/subject/27131969/", "title" : "无名狂", "actors" : 6, "director" : "李云波" }
{ "_id" : ObjectId("5f59929c69d6a3f8e726308e"), "url" : "https://movie.douban.com/subject/30129061/", "title" : "我想结束这一切 I'm Thinking of Ending Things", "actors" : 15, "director" : "查理·考夫曼" }
{ "_id" : ObjectId("5f59929d69d6a3f8e726308f"), "url" : "https://movie.douban.com/subject/30299515/", "title" : "釜山行2:半岛 부산행2-반도", "actors" : 8, "director" : "延尚昊" }
{ "_id" : ObjectId("5f59929d69d6a3f8e7263090"), "url" : "https://movie.douban.com/subject/26357307/", "title" : "花木兰 Mulan", "actors" : 27, "director" : "妮琪·卡罗" }
{ "_id" : ObjectId("5f5995018155a8757b4937eb"), "url" : "https://movie.douban.com/subject/30479644/", "title" : "铁雨2:首脑峰会 강철비2: 정상회담", "actors" : 27, "director" : "杨宇硕" }
{ "_id" : ObjectId("5f5995018155a8757b4937ec"), "url" : "https://movie.douban.com/subject/34462775/", "title" : "#活着 #살아있다", "actors" : 2, "director" : "赵一亨" }
{ "_id" : ObjectId("5f5995018155a8757b4937ed"), "url" : "https://movie.douban.com/subject/30330875/", "title" : "超能计划 Project Power", "actors" : 27, "director" : "亨利·朱斯特" }
{ "_id" : ObjectId("5f5995018155a8757b4937ee"), "url" : "https://movie.douban.com/subject/30129061/", "title" : "我想结束这一切 I'm Thinking of Ending Things", "actors" : 15, "director" : "查理·考夫曼" }
{ "_id" : ObjectId("5f5995018155a8757b4937ef"), "url" : "https://movie.douban.com/subject/27131969/", "title" : "无名狂", "actors" : 6, "director" : "李云波" }
{ "_id" : ObjectId("5f5995018155a8757b4937f0"), "url" : "https://movie.douban.com/subject/30289869/", "title" : "艾娃 Ava", "actors" : 18, "director" : "泰特·泰勒" }
{ "_id" : ObjectId("5f5995018155a8757b4937f1"), "url" : "https://movie.douban.com/subject/35141706/", "title" : "东北往事:我叫刘海柱", "actors" : 10, "director" : "周润泽" }
{ "_id" : ObjectId("5f5995018155a8757b4937f2"), "url" : "https://movie.douban.com/subject/26389321/", "title" : "新变种人 The New Mutants", "actors" : 14, "director" : "约什·布恩" }
{ "_id" : ObjectId("5f5995018155a8757b4937f3"), "url" : "https://movie.douban.com/subject/30299515/", "title" : "釜山行2:半岛 부산행2-반도", "actors" : 8, "director" : "延尚昊" }
{ "_id" : ObjectId("5f5995018155a8757b4937f4"), "url" : "https://movie.douban.com/subject/26357307/", "title" : "花木兰 Mulan", "actors" : 27, "director" : "妮琪·卡罗" }

参考资料



本文作者:大师兄(superkmi)

上一篇下一篇

猜你喜欢

热点阅读