文章目录
一、管道文件pipeline
1.pipeline的作用
- 清理html数据
- 验证爬取的数据
- 去重并丢弃
- 将爬取的结果保存到数据库中或文件中
2.简单使用一下管道pipeline
管道的作用是为了将spider爬虫拿到的字段数据进行一些处理
例如我们有个baidu_spider爬虫
import scrapy
class BaiduSpiderSpider(scrapy.Spider):
name = 'baidu_spider'
allowed_domains = []
start_urls = ['http://www.baidu.com']
def parse(self, response):
item = {
}
item['url'] = response.url
return item
然后我们在pipelines.py 文件中输出一下这个item
from itemadapter import ItemAdapter
class GubaScrapyPipeline:
def process_item(self, item, spider):
print(item)
return item
想要管道文件生效,需要配置一下:
运行一下:
scrapy crawl baidu_spider --nolog
成功输出结果,说明我们的爬虫文件的item成功传入了管道文件!
3.管道文件的多个类
问题:一个管道文件有多个管道类,如何能让item在不同类中传递呢?
添加一个管道类,修改管道文件。每个管道类中return item的意思是将处理过的item传给下一个管道类,如果不写return,那么下一个管道文件会处理空值。
from itemadapter import ItemAdapter
class GubaScrapyPipeline:
def process_item(self, item, spider):
print('我进入了管道类GubaScrapyPipeline')
return item
class GubaScrapyPipeline11111:
def process_item(self, item, spider):
print('我进入了管道类GubaScrapyPipeline111')
return item
修改配置文件,每个类后边的数字代表优先级,越小越先执行
运行一下
4.多个爬虫文件如何使用管道文件
问题:我们scrapy项目中一般会有多个爬虫项目,但是一般管道文件只有一个,那么当不同爬虫文件的item进入管道中,那么我们如何处理呢?
方法一:
假设我们有两个爬虫文件
为了区分管道item,我们在各自的爬虫里加入一个特殊的字段
管道文件修改为
from itemadapter import ItemAdapter
class GubaScrapyPipeline:
def process_item(self, item, spider):
if item['from_spider']=='baidu_spider':
print('我是处理百度爬虫的管道类')
return item
class GubaScrapyPipeline111:
def process_item(self, item, spider):
if item['from_spider'] == 'tencent_spider':
print('我是处理腾讯爬虫的管道类')
return item
方法二:
我们管道文件也可以对每个来源的爬虫进行判断
from itemadapter import ItemAdapter
class GubaScrapyPipeline:
def process_item(self, item, spider):
if spider.name == 'baidu_spider':
print('我是处理百度爬虫的管道类')
return item
class GubaScrapyPipeline111:
def process_item(self, item, spider):
if spider.name == 'tencent_spider':
print('我是处理腾讯爬虫的管道类')
return item
5.管道中的其他方法
open_spider(self,spider)
表示当spider被开启的时候调用这个方法
close_spider(self,spider)
当spider挂去年比时候这个方法被调用
from_crawler(cls,crawler)
这个可以用于获取settings配置文件中的信息,需要注意的这个是一个类方法,用法例子如下:
6.一些item pipeline的使用例子
例子1
这个例子是将item写入到json文件中
import json
class JsonWriterPipeline(object):
def __init__(self):
self.file = open('items.jl', 'wb')
def process_item(self, item, spider):
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
return item</pre>
例子2
将item写入到MongoDB,同时这里演示了from_crawler的用法
import pymongo
class MongoPipeline(object):
collection_name = 'scrapy_items'
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
self.db[self.collection_name].insert(dict(item))
return item</pre>
例子3:去重
一个用于去重的过滤器,丢弃那些已经被处理过的item,假设item有一个唯一的id,但是我们spider返回的多个item中包含了相同的id,去重方法如下:这里初始化了一个集合,每次判断id是否在集合中已经存在,从而做到去重的功能
from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item</pre>
7.注意事项
- 使用管道,必须要在settings.py文件中进行配置
- 配置文件中的管道配置时候的数字代表优先级,越小越先执行
- 管道类中的item传递必须通过return
- 管道类中的process_item(self, item, spider)才可以接收传过来的item,其他方法不可以
- 管道的作用一般就是处理接收过来的item,或者将接收的item存入数据库
- spider将值传入管道文件通过return,但是return的时候不可以retrun列表,一般就是字典
二、下载中间件middleware
1.常用的下载中间件方法
class RenrenDownloaderMiddleware:
def process_request(self, request, spider):
# 当每个request请求通过下载中间件时候调用的,可以不返回值,比如我们就单单的使用随机useragent和proxy时候
return None
def process_response(self, request, response, spider):
# 当我们下载器从网页上下载完http请求,调用的方法,必须要返回一个响应传给spider
return response
def process_exception(self, request, exception, spider):
#处理在使用下载器中间时候遇到的异常
pass
2.使用下载中间件写一个随机user-agent
问题:有时候我们爬取一个网站爬取太频繁,可能网站会通过判断user-agent判断是不是一个爬虫,我们因此可以通过随机user-agent来避免这种情况
1.在setting.py 加入我们的user-agent列表
USER_AGENT_LIST = [
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
'Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)'
]
2.在下载中间件middlewares.py文件中随机选择一个user-agent
import random
class RandomUserAgentMiddleware:
def process_request(self, request, spider):
ua=random.choice(self.settings.USER_AGENT_LIST)
request.headers["User-Agent"]=ua
3.在settings中启用下载中间件
DOWNLOADER_MIDDLEWARES = {
'renren.middlewares.RandomUserAgentMiddleware': 543,
}
4.在spider.py中输出看一下
结果:
常见的user-agent
1) Chrome
Win7:
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1
2) Firefox
Win7:
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0
3) Safari
Win7:
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50
4) Opera
Win7:
Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50
5) IE
Win7+ie9:
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)
Win7+ie8:
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3)
WinXP+ie8:
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)
WinXP+ie7:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
WinXP+ie6:
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
6) 傲游
傲游3.1.7在Win7+ie9,高速模式:
Mozilla/5.0 (Windows; U; Windows NT 6.1; ) AppleWebKit/534.12 (KHTML, like Gecko) Maxthon/3.0 Safari/534.12
傲游3.1.7在Win7+ie9,IE内核兼容模式:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)
7) 搜狗
搜狗3.0在Win7+ie9,IE内核兼容模式:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)
搜狗3.0在Win7+ie9,高速模式:
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.33 Safari/534.3 SE 2.X MetaSr 1.0
8) 360
360浏览器3.0在Win7+ie9:
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)
9) QQ浏览器
QQ浏览器6.9(11079)在Win7+ie9,极速模式:
Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 QQBrowser/6.9.11079.201
QQ浏览器6.9(11079)在Win7+ie9,IE内核兼容模式:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E) QQBrowser/6.9.11079.201
10) 阿云浏览器
阿云浏览器1.3.0.1724 Beta(编译日期2011-12-05)在Win7+ie9:
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
3.使用下载中间件写代理IP
步骤:
- 首先准备一些代理IP
- 一般我们对代理IP会有一个验证的过程,假设有一个代理IP的列表,定义一个函数,如果代理ip可以通过则没事,当代理IP不通过删除该代理IP,然后再进行正常的爬虫
- 然后写下载中间件,此处知识假设,真实不可能只有一个代理IP,一般是从代理ip列表随机选择
- 配置文件中激活下载中间件