新网创想网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
Scrapy简介
创新互联建站专业提供成都主机托管四川主机托管成都服务器托管四川服务器托管,支持按月付款!我们的承诺:贵族品质、平民价格,机房位于中国电信/网通/移动机房,资阳托管服务器服务有保障!Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。
基本功能
Scrapy是一个为遍历爬行网站、分解获取数据而设计的应用程序框架,它可以应用在广泛领域:数据挖掘、信息处理和或者历史片(历史记录)打包等等
尽管Scrapy原本是设计用来屏幕抓取(更精确的说,是网络抓取)的目的,但它也可以用来访问API来提取数据,比如Amazon的AWS或者用来当作通常目的应用的网络蜘蛛
Scrapy框架
Scrapy是用Python实现的一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘、信息处理或存储历史数据等一系列的程序中。
Scrapy使用Twisted基于事件的高效异步网络框架来处理网络通信,可以加快下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活的完成各种需求。
Scrapy架构
Scrapy Engine
引擎,负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。此组件相当于爬虫的“大脑”,是整个爬虫的调度中心
调度器(Scheduler)
调度器接收从引擎发送过来的request,并将他们入队,以便之后引擎请求他们时提供给引擎
初始的爬取URL和后续在页面中获取的待爬取的URL将放入调度器中,等待爬取。同时调度器会自动去除重复的URL(如果特定的URL不需要去重也可以通过设置实现,如post请求的URL)
下载器(Downloader)
下载器负责获取页面数据并提供给引擎,而后提供给spider
Spiders爬虫
Spider是编写的类,作用如下:
Scrapy用户编写用于分析response并提取item(即获取到的item)
额外跟进的URL,将额外跟进的URL提交给引擎,加入到Scheduler调度器中。将每个spider负责处理一个特定(或一些)网站
Item Pipeline
Item Pipeline负责处理被spider提取出来的item。典型的处理有清理、 验证及持久化(例如存取到数据库中)
当页面被爬虫解析所需的数据存入Item后,将被发送到项目管道(Pipeline),并经过设置好次序的pipeline程序处理这些数据,最后将存入本地文件或存入数据库
类似管道 $ ls | grep test 或者类似于Django 模板中的过滤器
以下是item pipeline的一些典型应用:
清理HTML数据
验证爬取的数据(检查item包含某些字段)
查重(或丢弃)
将爬取结果保存到数据库中
下载器中间件(Downloader middlewares)
简单讲就是自定义扩展下载功能的组件。
下载器中间件,是在引擎和下载器之间的特定钩子(specific hook),处理它们之间的请求request和响应response。
它提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能
通过设置下载器中间件可以实现爬虫自动更换user-agent、IP等功能
Spider中间件(Spider middlewares)
Spider中间件,是在引擎和Spider之间的特定钩子(specific hook),处理spider的输入(response)和输出(items或requests)。
也提供了同样的简便机制,通过插入自定义代码来扩展Scrapy功能。
数据流(Data flow)
1.引擎打开一个网站(open a domain),找到处理该网站的Spider并向该spider请求第一个(批)要爬取的URL(s)
2.引擎从Spider中获取到第一个要爬取的URL并加入到调度器(Scheduler)作为请求以备调度
3.引擎向调度器请求下一个要爬取的URL
4.调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件并转发给下载器(Downloader)
5.一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件发送给引 擎
6.引擎从下载器中接收到Response,然后通过Spider中间件发送给Spider处理
7.Spider处理Response并返回提取到的Item及(跟进的)新的Request给引擎
8.引擎将Spider返回的Item交给Item Pipeline,将Spider返回的Request交给调度器
9.(从第二步)重复执行,直到调度器中没有待处理的request,引擎关闭
注意:
只有当调度器中没有任何request了,整个程序才会停止执行。如果有下载失败的URL,会重新下载
安装scrapy
安装wheel支持
$ pip install wheel
安装scrapy框架
$ pip install scrapy
window下,为了避免windows编译安装twisted依赖,安装下面的二进制包
$ pip install Twisted-18.4.0-cp35-cp35m-win_amd64.whl
windows下出现如下问题:
copying src\twisted\words\xish\xpathparser.g -> build\lib.win-amd64-3.5\twisted\words\xish running build_ext building 'twisted.test.raiser' extension error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools解决方案是,下载编译好的twisted,Python Extension Packages for Windowspython3.5 下载 Twisted-18.4.0-cp35-cp35m-win_amd64.whlpython3.6 下载 Twisted-18.4.0-cp36-cp36m-win_amd64.whl安装twisted$ pip install Twisted-18.4.0-cp35-cp35m-win_amd64.whl之后在安装scrapy就没有什么问题了安装好,使用scrapy命令看看
1.> scrapy 2.Scrapy 1.5.0 - no active project 3. 4.Usage: 5. scrapyScrapy开发
项目编写流程
1.创建项目
使用 scrapy startproject proname 创建一个scrapy项目
scrapy startproject
2.编写item
在items.py中编写Item类,明确从response中提取的item
3.编写爬虫
编写spiders/proname_spider.py,即爬取网站的spider并提取出item
4.编写item pipeline
item的处理,可以存储
1 创建项目
1.1 豆瓣书评爬取
标签为“编程”,第一页、第二页链接:
https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start=0&type=T
https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start=20&type=T
随便找一个目录来创建项目,执行下面命令
$ scrapy startproject first .
会产生如下目录和文件
first ├─ scrapy.cfg └─ first ├─ items.py ├─ middlewares.py ├─ pipelines.py ├─ settings.py ├─ __init__.py └─ spiders └─ __init__.pyfirst:
外部的first目录是整个项目目录,内部的first目录是整个项目的全局目录
scrapy.cfg:
必须有的重要的项目的配置文件
first 项目目录
__init__.py 必须有,包文件
items.py 定义Item类,从scrapy.Item继承,里面定义scrapy.Field类实例
pipelines.py 重要的是process_item()方法,处理item
settings.py:
BOT_NAME 爬虫名
ROBOTSTXT_OBEY = True 是否遵从robots协议
USER_AGENT = '' 指定爬取时使用
CONCURRENT_REQEUST = 16 默认16个并行
DOWNLOAD_DELAY = 3 下载延时,一般要设置,不宜过快发起连续请求
COOKIES_ENABLED = False 缺省是启用,一般需要登录时才需要开启cookie
SPIDER_MIDDLEWARES 爬虫中间件
DOWNLOADER_MIDDLEWARES 下载中间件
'firstscrapy.pipelines.FirstscrapyPipeline': 300item交给哪一个管道处理,300 越小优先
级越高
ITEM_PIPELINES 管道配置
'first.middlewares.FirstDownloaderMiddleware': 543543 越小优先级越高
spiders目录
__init__.py 必须有,可以在这里写爬虫类,也可以写爬虫子模块
1.# first/settings.py参考2.BOT_NAME = 'first'3.SPIDER_MODULES = ['first.spiders']4.NEWSPIDER_MODULE = 'first.spiders'5.6.USER_AGENT = "Mozilla/5.0 (Windows NT 6.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36"7.ROBOTSTXT_OBEY = False8.9.DOWNLOAD_DELAY = 310.11.# Disable cookies (enabled by default)12.COOKIES_ENABLED = False注意一定要更改User-Agent,否则访问https://book.douban.com/会返回403
2 编写Item
1.在items.py中编写 2.import scrapy 3.class BookItem(scrapy.Item): 4.title = scrapy.Field() # 书名 5.rate = scrapy.Field() # 评分3 编写爬虫
为爬取豆瓣书评编写爬虫类,在spiders目录下:
编写的爬虫类需要继承自scrapy.Spider,在这个类中定义爬虫名、爬取范围、其实地址等
在scrapy.Spider中parse方法未实现,所以子类应该实现parse方法。该方法传入response对象
爬取读书频道,tag为“编程”的书名和评分:
https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start=20&type=T
使用模板创建spider, $ scrapy genspider -t basic book https://www.douban.com/
1.import scrapy 2. 3.class BookSpider(scrapy.Spider): # BookSpider 4.name = 'doubanbook' # 爬虫名,可修改,重要 5.allowed_domains = ['豆瓣'] # 爬虫爬取范围 6.url = '豆瓣图书标签: 编程' 7.start_urls = [url] # 起始URL 8. 9.# 下载器获取了WEB Server的response就行了,parse就是解析响应的内容 10.def parse(self, response): 11. print(type(response), '~~~~~~~~~') #scrapy.http.response.html.HtmlResponse 12.print(response) 13.print('-' * 30)使用crawl爬取子命令
1.$ scrapy list 2.$ scrapy crawl -h 3.scrapy crawl [options]如果在windows下运行发生twisted的异常 ModuleNotFoundError: No module named 'win32api' ,请安装 $ pip install pywin32。
response是服务器端HTTP响应,它是scrapy.http.response.html.HtmlResponse类。
由此,修改代码如下
1.import scrapy 2.from scrapy.http.response.html import HtmlResponse 3. 4.class BookSpider(scrapy.Spider): # BookSpider 5. name = 'doubanbook' # 爬虫名 6. allowed_domains = ['豆瓣'] # 爬虫爬取范围 7. url = '豆瓣图书标签: 编程' 8.start_urls = [url] # 起始URL 9. 10. # 下载器获取了WEB Server的response就行了,parse就是解析响应的内容 11.def parse(self, response:HtmlResponse): 12. print(type(response)) #scrapy.http.response.html.HtmlResponse 13. print('-'*30) 14. print(type(response.text), type(response.body)) 15.print('-'*30) 16.print(response.encoding) 17.with open('o:/testbook.html', 'w', encoding='utf-8') as f: 18. try: 19. f.write(response.text) 20. f.flush() 21. except Exception as e: 22.print(e)3.1 解析HTML
爬虫获得的内容response对象,可以使用解析库来解析。
scrapy包装了lxml,父类TextResponse类也提供了xpath方法和css方法,可以混合使用这两套接口解析HTML。
选择器参考:
https://scrapy-chs.readthedocs.io/zh_CN/0.24/topics/selectors.html#id3
1.import scrapy 2.from scrapy.http.response.html import HtmlResponse 3. 4.response = HtmlResponse('file:///O:/testbook.html', encoding='utf-8') # 构造对象 5. 6.with open('o:/testbook.html', encoding='utf8') as f: 7.response._set_body(f.read()) # 填充数据 8.#print(response.text) 9. 1O.# 获取所有标题及评分 11.# xpath解析 12.subjects = response.xpath('//li[@class="subject-item"]') 13.for subject in subjects: 14.title = subject.xpath('.//h3/a/text()').extract() # list 15.print(title[0].strip()) 16. 17.rate = subject.xpath('.//span[@class="rating_nums"]/text()').extract() 18.print(rate[0].strip()) 19. 2O.print('-'*30) 21.# css解析 22.subjects = response.css('li.subject-item') 23.for subject in subjects: 24.title = subject.css('h3 a::text').extract() 25.print(title[0].strip()) 26. 27.rate = subject.css('span.rating_nums::text').extract() 28.print(rate[0].strip()) 29.print('-'*30) 30. 31. # xpath和css混合使用、正则表达式匹配 32.subjects = response.css('li.subject-item') 33.for subject in subjects: 34.# 提取链接 35.href =subject.xpath('.//h3').css('a::attr(href)').extract() 36.print(href[0]) 37. 38. # 使用正则表达式 39.id = subject.xpath('.//h3/a/@href').re(r'\d*99\d*') 40.if id: 41.print(id[0]) 42. 43.# 要求显示9分以上数据 44.rate = subject.xpath('.//span[@class="rating_nums"]/text()').re(r'^9.*') 45.# rate = subject.css('span.rating_nums::text').re(r'^9\..*') 46.if rate: 47.print(rate)3.2 item封装数据
1.# spiders/bookspider.py 2.import scrapy 3.from scrapy.http.response.html import HtmlResponse 4.from ..items import BookItem 5. 6.class BookSpider(scrapy.Spider): # BookSpider 7.name = 'doubanbook' # 爬虫名 8.allowed_domains = ['豆瓣'] # 爬虫爬取范围 9.url = '豆瓣图书标签: 编程' 10.start_urls = [url] # 起始URL 11. 12. # 下载器获取了WEB Server的response就行了,parse就是解析响应的内容 13.def parse(self, response:HtmlResponse): 14.items = [] 15.# xpath解析 16.subjects = response.xpath('//li[@class="subject-item"]') 17.for subject in subjects: 18.title = subject.xpath('.//h3/a/text()').extract() 19.rate = subject.xpath('.//span[@class="rating_nums"]/text()').extract_first() 20.item = BookItem() 21.item['title'] = title[0].strip() 22.item['rate'] = rate.strip() 23. items.append(item) 24. 25. print(items) 26. 27.return items # 一定要return,否则保存不下来 28. 29.# 使用命令保存return的数据 30.# scrapy crawl -h 31.# --output=FILE, -o FILE dump scraped items into FILE (use - for stdout) 32.# 文件扩展名支持'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle' 33.# scrapy crawl doubanbook -o dbbooks.json得到下图数
注意上图的数据已经是unicode字符,汉字的unicode表达。
4 pipeline处理
将bookspider.py中BookSpider改成生成器,只需要把 return items 改造成 yield item ,即由产生一个列表变成yield一个个item
脚手架帮我们创建了一个pipelines.py文件和一个类
4.1 开启pipeline
1.# Configure item pipelines 2.# See Item Pipeline - Scrapy 1.8.0 documentation 3.ITEM_PIPELINES = { 4.'first.pipelines.FirstPipeline': 300, 5.}整数300表示优先级,越小越高。
取值范围为0-1000
4.2常用方法
1.class FirstPipeline(object): 2.def __init__(self): # 全局设置 3. print('~~~~~~~~~~ init ~~~~~~~~~~~~') 4. 5.def open_spider(self, spider): # 当某spider开启时调用 6. print(spider,'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~') 7. 8.def process_item(self, item, spider): 9. # item 获取的item;spider 获取该item的spider 10.return item 11. 12.def close_spider(self, spider): # 当某spider关闭时调用 13.print(spider,'========================================') 14.需求
通过pipeline将爬取的数据存入json文件中
1.# spider/bookspider.py 2.import scrapy 3.from scrapy.http.response.html import HtmlResponse 4.from ..items import BookItem 5. 6.class BookSpider(scrapy.Spider): # BookSpider 7. name = 'doubanbook' # 爬虫名 8. allowed_domains = ['豆瓣'] # 爬虫爬取范围 9.url = '豆瓣图书标签: 编程' 10. start_urls = [url] # 起始URL 11. 12.# spider上自定义配置信息 13.custom_settings = { 14. 'filename' : 'o:/books.json' 15. } 16.# 下载器获取了WEB Server的response就行了,parse就是解析响应的内容 17.def parse(self, response:HtmlResponse): 18. #items = [] 19.# xpath解析 20.subjects = response.xpath('//li[@class="subject-item"]') 21.for subject in subjects: 22.title = subject.xpath('.//h3/a/text()').extract() 23.rate =subject.xpath('.//span[@class="rating_nums"]/text()').extract_first() 24.item = BookItem() 25.item['title'] = title[0].strip() 26.item['rate'] = rate.strip() 27.#items.append(item) 28. 29.yield item 30.#return items 31. 32.# pipelines.py 33.import simplejson as json 34. 35.class FirstPipeline(object): 36. def __init__(self): # 全局设置 37. print('~~~~~~~~~~ init ~~~~~~~~~~~~') 38. 39.def open_spider(self, spider): # 当某spider开启时调用 40. print('{} ~~~~~~~~~~~~~~~~~~~~'.format(spider)) 41. print(spider.settings.get('filename')) 42.self.file = open(spider.settings['filename'], 'w', encoding='utf-8') 43.self.file.write('[\n') 44. 45.def process_item(self, item, spider): 46.# item 获取的item;spider 获取该item的spider 47.self.file.write(json.dumps(dict(item)) + ',\n') 48.return item 49. 50.def close_spider(self, spider): # 当某spider关闭时调用 51.self.file.write(']') 52.self.file.close() 53.print('{} ======================='.format(spider)) 54.print('-'*30)5 url提取
如果要爬取下一页内容,可以自己分析每一页的页码变化,也可以通过提取分页栏的链接
1.# spider/bookspider.py 2.import scrapy 3.from scrapy.http.response.html import HtmlResponse 4.from ..items import BookItem 5. 6.class BookSpider(scrapy.Spider): # BookSpider 7.name = 'doubanbook' # 爬虫名 8.allowed_domains = ['豆瓣'] # 爬虫爬取范围 9.url = '豆瓣图书标签: 编程' 10.start_urls = [url] # 起始URL 11. 12.# spider上自定义配置信息 13.custom_settings = { 14.'filename' : 'o:/books.json' 15.} 16. 17.# 下载器获取了WEB Server的response就行了,parse就是解析响应的内容 18.def parse(self, response:HtmlResponse): 19.#items = [] 20.# xpath解析 21.# 获取下一页,只是测试,所以使用re来控制页码 22.print('-' * 30) 23.urls = response.xpath('//div[@class="paginator"]/span[@class="next"]/a/@href').re( 24. r'.*start=[24]\d[^\d].*') 25.print(urls) 26.print('-' * 30) 27.yield from (scrapy.Request(response.urljoin(url)) for url in urls) 28.print('++++++++++++++++++++++++') 29. 30.subjects = response.xpath('//li[@class="subject-item"]') 31.for subject in subjects: 32.# 解决图书副标题拼接 33.title = "".join(map(lambda x:x.strip(), subject.xpath('.//h3/a//text()').extract())) 34.rate = subject.xpath('.//span[@class="rating_nums"]/text()').extract_first() 35.#print(rate) # 有的没有评分,要注意可能返回None 36. 37.item = BookItem() 38.item['title'] = title 39.item['rate'] = rate 40.#items.append(item) 41.yield item 42. 43.#return items另外有需要云服务器可以了解下创新互联cdcxhl.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。