## scrapy 依赖 twisted
- twisted 是一个基于事件循环的 异步非阻塞 框架/模块
## 项目的创建
1. 创建 project scrapy startproject 项目名称 项目名称(项目结构) - spiders # 爬虫文件 - q.py - w.py - items.py # 持久化 - pipelines # 持久化 - middlewares.py # 中间件 - settings.py # 配置文件(爬虫) scrapy.cfg # 配置文件(部署) 2. 创建爬虫 cd 项目名称 scrapy genspider q q.com scrapy genspider w w.com 3. 启动爬虫 scrapy crawl q --nolog # 不查看日志 scrapy crawl w # 默认查看日志
## pipeline 做持久化
- pipeline 是所有爬虫公用的,如果想要给某个爬虫制定需要使用 spider 参数进行判断处理:
if spider.name == 'xxx'
1. 自定义的爬虫文件中 将每次获取到的数据 传给 ScrapyDeom1Item 类方法 for item in item_list: href = item.xpath('.//a/@href').extract_first() txt = item.xpath('.//a/text()').extract_first() yield ScrapyDeom1Item(text=txt, href=href) 2. items 中 ScrapyDeom1Item 类方法 将需要存储的数据接收到。 class ScrapyDeom1Item(scrapy.Item): href = scrapy.Field() text = scrapy.Field() 3. settings 中定义做持久化的类( ScrapyDeom1Pipeline ) 和 定义一个文件路径 ITEM_PIPELINES = { 'scrapy_deom1.pipelines.ScrapyDeom1Pipeline': 300, # 文件路径 # 优先级( 1-1000 ) } PATH = 'new.log' 4. 到 pipelines.py 文件中 找到 ScrapyDeom1Pipeline 类并做持久化 from scrapy.exceptions import DropItem class ScrapyDeom1Pipeline(object): def __init__(self, path): # 初始化定义文件操作 和 文件要保存的路径 self.f = None self.path = path @classmethod def from_crawler(cls, crawler): """ 初始化的时候,用来创建 pipeline 对象 :param crawler: :return: """ # 去settings 寻找要保存的文件路径 path = crawler.settings.get('PATH') return cls(path) def open_spider(self, spider): """ 爬虫刚启动时调用 - 此处用来做打开文件操作 :param spider: :return: """ self.f = open(self.path, 'a+') def process_item(self, item, spider): """ 爬虫执行中调用 - 此处用来做将数据写入文件 操作 :param item: :param spider: :return: """ self.f.write(item['href']+' ') # raise DropItem() # 抛出异常,使后续的 pipeline 的 process_item 方法不执行 return item # 这个 item 是要返回给下个类的 def close_spider(self, spider): """ 爬虫执行完毕后调用 - 此处用来做关闭文件操作 :param spider: :return: """ self.f.close()
## 去重
1. 创建一个 dupefilters.py 文件(用于做去重操作): from scrapy.dupefilters import BaseDupeFilter from scrapy.utils.request import request_fingerprint class MyDupeFilter(BaseDupeFilter): def __init__(self): self.visited_fd = set() @classmethod def from_settings(cls, settings): return cls() def request_seen(self, request): """ 判断当前请求的URL是否存在 - 用于去重 - 如果存在则 pass - 如不存在则 添加 :param request: :return: """ # 将当前 URL 加密成一定位数的字符 print(request) fd = request_fingerprint(request=request) if fd in self.visited_fd: return True self.visited_fd.add(fd) def open(self): # can return deferred """ 执行前的一些操作 :return: """ print('爬虫开始') def close(self, reason): # can return a deferred """ 执行结束后的一些操作 :param reason: :return: """ print('爬虫结束') def log(self, request, spider): # log that a request has been filtered """ 访问的每一个 URL 的日志信息 :param request: :param spider: :return: """ pass 2. settings 中注册这个类 DUPEFILTER_CLASS = 'scrapy_demo1.dupefilters.MyDupeFilter' 3. 可以设置是否使用当前定义的去重方法 # True 表示不使用 # False 表示使用 (默认为False) yield Request(url=page, callback=self.parse, dont_filter=True)
## 限制深度查询
配置文件中(settings): DEPTH_LIMIT = 3 # 查询深度设置为三层
## Cookie
# 解析 cookie
cookie_jar = CookieJar()
cookie_jar.extract_cookies(response, response.request)
# 去对象中将cookie解析到字典
for k, v in cookie_jar._cookies.items():
for i, j in v.items():
for m, n in j.items():
self.cookie_dict[m] = n.value
# 获取 cookie
cookies=self.cookie_dict,