填坑计划:scrapy
scrapy简介
Scrapy是适用于Python的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。
ScrapyDemo
-
安装scrapy
pip3 install scrapy
-
创建scrapy项目
在项目目录下:scrapy startproject ScrapyDemo
-
使用PyCharm打开项目
为了操作方便,在项目根目录下创建run.py,以用于后面的启动和调试项目# -*- coding: utf-8 -*- # 启动项目脚本 from scrapy.cmdline import execute # 创建爬虫 execute('scrapy genspider qidian_bookinfo "book.qidian.com"'.split())
可以看到:使用scrapy.cmdline.execute方法执行命令行指令,需要使用split函数将指令分隔开
-
创建爬虫
在项目目录下执行指令scrapy genspider qidian_bookinfo "book.qidian.com"
创建一个爬虫,爬取的范围是起点小说网的book目录,本次就先拿这个作为实验对象
-
创建item对象
在Items.py文件中,按照提示创建内容
我们计划爬取某小说的题目、作者、宣传语、简介内容四个部分,因此要创建4个Itemimport scrapy class ScrapydemoItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() author = scrapy.Field() intro = scrapy.Field() entry = scrapy.Field()
-
编写爬虫文件qidian_bookinfo.py
# -*- coding: utf-8 -*- import scrapy from ScrapyDemo.items import ScrapydemoItem # 具体爬虫文件 class QidianBookinfoSpider(scrapy.Spider): name = 'qidian_bookinfo' # 允许爬取的域名范围 allowed_domains = ['book.qidian.com'] # 开始爬取url start_urls = ['https://book.qidian.com/info/1004990267/'] def parse(self, response): title = response.xpath('//div[@class="book-info "]//h1//em/text()').get() author = response.xpath('//div[@class="book-info "]//h1//span//a/text()').get() intro = response.xpath('//div[@class="book-info "]//p[@class="intro"]/text()').get() entry = response.xpath('//div[@class="book-intro"]//p/text()').get().strip() # 返回对象 item = ScrapydemoItem(title=title, author=author, intro=intro, entry=entry) # 生成item yield item
可以看到,这里使用的xpath作为选择器,因此需要先了解xpath语法
xpath语法参考
其实理解起来比较容易,比如下面的xpath解析式://div[@class="book-info "]//h1//em/text()
解析的对象是class="book-info "的div的下面的h1,h1下面的em标签中的文本内容,这个内容就是作品题目
注意: 这里作者遇到了一个坑点(和程序无关),这个网站的info页面book-info类的div标签类是带一个空格的,笔者一开始去掉了空格,结果什么都爬不到、
[@class="book-info "] #字符串最后有个空格是故意加上的,不加空格爬取不到
-
使用pipline处理内容
在pipline.py文件中处理爬虫返回的内容,这里将获得的四种信息转换成json格式并且存储到本地文件
使用了scrapy中专门输出Json格式数据的JsonLinesItemExporter来输出数据
from scrapy.exporters import JsonLinesItemExporter
class ScrapydemoPipeline:
def __init__(self):
self.fp = open("bookinfo.json", "wb")
# json文件输出器
self.exporter = JsonLinesItemExporter(self.fp, ensure_ascii=False, encoding='utf-8')
def open_spider(self, spider):
self.exporter.start_exporting()
def process_item(self, item, spider):
self.exporter.export_item(item)
return item
def close_spider(self, spider):
self.fp.close()
self.exporter.finish_exporting()
print("结束")
- 配置settings.py
在我们写好了所有内容之后,爬虫需要进行配置才能运行
编辑settings.py,取消注释并且配置一下内容:# 1. 关闭遵守robots协议 ROBOTSTXT_OBEY = False # 2. 伪装身份 DEFAULT_REQUEST_HEADERS = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36' } # 3. 使用pipeline处理获取数据 ITEM_PIPELINES = { 'ScrapyDemo.pipelines.ScrapydemoPipeline': 300, }
- 在run.py中运行如下内容,即可启动爬虫
#执行指令 execute('scrapy crawl qidian_bookinfo'.split())
- 检查目录下的bookinfo.json结果
使用JsonLinesItemExporter输出的数据如果有多个会占多行,每行是独立的json数据{ "title": "穿越之皇帝成长计划", "author": "奥特曼会写字", "intro": "醒掌天下权,醉卧美人膝,五千年风华烟雨,是非成败转头空!", "entry": "主角一朝穿越惊现成了即将登位的太子,治理自己的国家。寻找名妃,培养子女,尔虞我诈;发展国家,收录名臣,秣马厉兵。是后宫佳丽三千还是后宫佳丽三千;西楚霸王、蜀汉名将、水浒英雄,谁能助我一统天下;从三皇五帝到唐宗宋祖,雄霸天下亦或是儿女情长,收录不尽的名臣美人,挑战无限的激情国战。" }
如果使用JsonItemExporter输出数据,多行数据是装在一个json列表里的,只占一行