一,简介
- Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广泛。
- 框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便。
- Scrapy 使用了 Twisted(其主要对手是Tornado)异步网络框架来处理网络通讯,可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活的完成各种需求。
scrapy框架的请求流程:
- ScrapyEngine(引擎):负责 spider、 ItemPipeline、Downloader、Scheduler 中间的通讯, 信号、数据传递等。
-Scheduler(调度器):它负责接受引擎发送过来的 Request 请求,并按照一定的方式进 行整理排列,入队,当引擎需要时,交还给引擎。 - Downloader(下载器):负责下载 ScrapyEngine(引擎)发送的所有 Requests 请求,并将 其获取到的 Responses 交还给 ScrapyEngine(引擎),由引擎交给 spider 来处理。
- spider(爬虫):它负责处理所有 Responses,从中分析提取数据,获取 Item 字段需要 的数据,并将需要跟进的 URL 提交给引擎,再次进入 Scheduler(调度器)。
- ItemPipeline(管道):它负责处理 spider 中获取到的 Item,并进行后期处理(详细分析、 过滤、存储等)。
- DownloaderMiddlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能 的组件。
- SpiderMiddlewares(spider 中间件):你可以理解为是一个可以自定义扩展和操作引擎 和 spider 中间通信的功能组件(比如进入 spider 的 Response 和从 spider 出去的 Requests)。
笔者在这用一个小故事来阐明请求流程:
-
引擎:Hi!spider,你要处理哪一个网站?
-
spider:老大要我处理 xxxx.com。
-
引擎:你把第一个需要处理的 URL 给我吧。
-
spider:给你,第一个 URL 是 xxxxxxx.com。
-
引擎:Hi!调度器,我这有 request 请求你帮我排序入队一下。
-
调度器:好的,正在处理你等一下。
-
引擎:Hi!调度器,把你处理好的 request 请求给我。
-
调度器:给你,这是我处理好的 request。
-
引擎:Hi!下载器,你按照老大的下载中间件的设置帮我下载一下这个 request 请求
-
下载器:好的!给你,这是下载好的东西。(如果失败:sorry,这个 request 下载失败了。 然后引擎告诉调度器,这个 request 下载失败了,你记录一下,我们待会儿再下载)
-
引擎:Hi!spider,这是下载好的东西,并且已经按照老大的下载中间件处理过了,你 自己处理一下(注意!这儿 responses 默认是交给 defparse()这个函数处理的)
-
spider:(处理完毕数据之后对于需要跟进的 URL),Hi!引擎,我这里有两个结果,这 个是我需要跟进的 URL,还有这个是我获取到的 Item 数据。
-
引擎:Hi!管道我这儿有个 item 你帮我处理一下!调度器!这是需要跟进 URL 你帮我 处理下。然后从第四步开始循环,直到获取完老大需要全部信息。
-
管道``调度器:好的,现在就做! 注意:只有当调度器中不存在任何 request 了,整个程序才会停止(也就是说,对于下载 失败的 URL,Scrapy 也会重新下载。)
二,安装
输入命令:python -m pip install scrapy -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
三,入门
以虎扑新闻为例:
创建scrapy项目:scrapy startproject [项目名]
创建项目成功后出现:
进入hupu
输入创建爬虫spider组件命令:scrapy genspider [spider的名称] www
打开items.py
输入要爬取的信息:
import scrapy
class HupuItem(scrapy.Item):
# define the fields for your item here like:
news_title = scrapy.Field()
news_from = scrapy.Field()
news_pub_time = scrapy.Field()
news_content = scrapy.Field()
news_imgs = scrapy.Field()
detail_url = scrapy.Field()
pass
打开settings.py
打开pipelines.py
链接Mongodb数据库
import pymongo
class HupuPipeline(object):
def __init__(self):
self.client = pymongo.MongoClient()
self.db =self.client['hupu_news']
def process_item(self, item, spider):
self.db['NBA'].update({'detail_url':item['detail_url']},{'$set':dict(item)},True)
print(item)
return item
最后打开hupu.spider.py
编写爬取内容
# -*- coding: utf-8 -*-
import scrapy
from ..items import HupuItem
class HupuSpiderSpider(scrapy.Spider):
# spider名称--将来运行的时候需要这个名字
name = 'hupu_spider'
# 二次请求会通过这个allowed_domains的内容进行过滤
# allowed_domains = ['www']
# scrapy启动之后,就会从这个start_urls列表里面取url进行【自动下载】,下载好的response就交给
# 下载的parse方法来处理
start_urls = []
for i in range(1,30):
base_url = 'https://voice.hupu.com/nba/%s' %i
start_urls.append(base_url)
def parse(self, response):
# 在parse方法中解析内容
# print(response.text)
# pass
# 进入列表页面:目标提取url
# print(response)#<200 https://voice.hupu.com/nba/13>
url_list = response.xpath('//div[@class="news-list"]/ul/li/div/h4/a/@href').extract()
# print(url_list)
# <Selector xpath='//div[@class="news-list"]/ul/li//a/@href' data='https://bbs.hupu.com/35672999.html'>,
for url in url_list:
# 当yield出去之后,scrapy就会接受这个request对象进行下载
# callback:将来scrapy下载好的response对象交给callback处理
# 也就是说必须有一个参数:response
yield scrapy.Request(url=url,callback=self.parse_detail,encoding='utf-8')
def parse_detail(self,response):
# 解析详情页的逻辑
# print(response.url)
news_title = response.xpath('//h1[@class="headline"]/text()').extract_first().strip()
# print(news_title)
news_from = response.xpath('//span[@id="source_baidu"]/a/text()').extract_first()
# print(news_from)
news_pub_time = response.xpath('//*[@id="pubtime_baidu"]/text()').extract_first()
# print(news_pub_time)
news_content = response.xpath('string(//div[@class="artical-main-content"])').extract_first()
news_imgs = response.xpath('//div[@class="artical-main-content"]//img/@src').extract()
# print(news_imgs)
# print(news_content)
item = HupuItem()
item['news_title'] = news_title
item['news_from'] = news_from
item['news_pub_time'] = news_pub_time
item['news_content'] = news_content
item['news_imgs'] = news_imgs
item['detail_url'] = response.url
# print(item)
yield item
运行命令:
查看保存的数据:
scrapy crawl [要爬取的spider名称] --nolog 带日志
scrapy crawl [要爬取的spider名称] 不带日志