scrapy框架是基于python的一个爬虫框架,官方文档链接:https://doc.scrapy.org/en/latest/
关于scrapy的安装参考之前的文章 Scrapy 框架的安装(Windows10)
下面以爬取简书的专题页为例说明scrapy框架的使用
我们这次抓取@IT·互联网的专题系列文章,如下图:
image.png
该页面的链接是http://www.jianshu.com/c/V2CqjW
然后试着用鼠标滚动页面,发现在页面快要滑倒底部时,触发了加载下一页的事件,而此时浏览器地址栏的url并未改变,说明这个页面的页面跳转是通过ajax来实现的,那么js脚本真正执行请求的url是多少呢,通过抓包可以获取这个url。
抓包可以使用fiddler,也可以使用chrome自带的网络工具,这里使用fiddler来抓取这个url,打开fiddler滑动页面到底部,结果下图所示:
image.png
可以清晰的看出请求url是http://www.jianshu.com/c/V2CqjW?order_by=added_at&page=0,通过改变page的值可以实现分页抓取数据
获取了url之后,我们来分析下页面的元素,看看我们希望抓取的文章信息在页面上是怎么显示的,使用chrome自带的分析工具来分析页面元素,选择需要查看的位置右键鼠标检查即可打开页面元素分析页,如下所示:
image.png
如上,可以很方便的找出文章列表是用一个ul标签实现的,里面的每一个文章都是一个li。
好了,简单的分析了页面元素后,我们开始着手搭建一个scrapy框架,进入一个希望存放项目的路径,地址栏输入cmd回车,打开window控制台,输入指令
scrapy startproject jianshu
创建了一个名字为简书的项目,使用pycharm打开项目,项目结构如下所示:
image.png
在items.py文件中定义一个实体类JianshuItem:
import scrapy
class JianshuItem(scrapy.Item):
# id, 使用mongodb,用_id作为主键
_id = scrapy.Field()
# 博客名
blog_title = scrapy.Field()
# 作者
author = scrapy.Field()
# 发布时间
date = scrapy.Field()
# 内容url
content_url = scrapy.Field()
# 内容简介
content_summary = scrapy.Field()
# 配图,可以为空
content_figure_url = scrapy.Field()
# 作者头像,可以为空
author_icon_url = scrapy.Field()
然后我们来实现一下爬虫类的编写,可以在spider文件夹下创建一个py文件用来实现爬虫逻辑,也可以使用命令直接创建一个:
scrapy genspider jianshuspider www.jianshu.com
创建格式如下:
scrapy genspider [options] <name> <domain>
这样就在spider文件夹下创建了一个名字叫jianshuspider.py的文件,我们在这个文件中实现爬虫的逻辑,代码如下:
# -*- coding: utf-8 -*-
import scrapy
from jianshu.items import JianshuItem
from abc import abstractmethod
class JianshuBaseSpider(scrapy.Spider):
base_url = "www.jianshu.com"
allowed_domains = [base_url]
category_code = ''
common_url = ''
url = ''
@abstractmethod
def parse_more(self):
pass
def get_full_url(self, url):
return self.base_url + url
def parse(self, response):
for i in response.xpath("//ul[@class='note-list']/li"):
item = JianshuItem()
try:
item['_id'] = i.xpath("./@id").extract()[0]
except Exception as e:
print(e)
return
try:
item['blog_title'] =
i.xpath(".//div[@class='content']/a/text()").extract()[0]
except Exception as e:
item['blog_title'] = ''
try:
item['content_url'] =
self.get_full_url(i.xpath(".//div[@class='content']/a/@href")
.extract()[0])
except Exception as e:
item['content_url'] = ''
try:
item['content_summary'] =
i.xpath(".//div[@class='content']/p/text()").extract()[0]
except Exception as e:
item['content_summary'] = ''
try:
item['content_figure_url'] =
self.get_full_url(i.xpath("./a/img/@src").extract()[0])
except Exception as e:
item['content_figure_url'] = ''
try:
item['author'] =
i.xpath(".//div[@class='author']/div/a/text()").extract()[0]
except Exception as e:
item['author'] = ''
try:
item['date'] = i.xpath(".//div[@class='author']/div/span/@data-
shared-at").extract()[0]
except Exception as e:
item['date'] = ''
try:
item['author_icon_url'] =
self.get_full_url(i.xpath(".//div[@class='author']/a/@href")
.extract()[0])
except Exception as e:
item['author_icon_url'] = ''
yield item
# 交由子类实现具体的处理
yield self.parse_more()
'''@IT·互联网 专题'''
class ITSpider(JianshuBaseSpider):
name = 'ITSpider'
page = 0
category_code = 'V2CqjW'
common_url = 'http://www.jianshu.com/c/' + category_code + '?
order_by=added_at&page='
url = common_url + str(page)
start_urls = [url]
def parse_more(self):
self.page += 1
# 每天抓20页
if self.page > 20:
return
return scrapy.Request(self.common_url + str(self.page),
callback=self.parse)
代码很简单,此处不再废话了,代码中使用了yield语句,用途是将结果提交到管道流pipeline,管道流来帮我们实现数据的持久化处理,打开pipeline.py文件,添加如下代码:
from pymongo import MongoClient
class JianshuPipeline(object):
def __init__(self):
self.client = MongoClient('localhost', 27017)
self.db_jianshu = self.client.jianshu
def process_item(self, item, spider):
json_item = dict(item)
self.db_jianshu.jianshu.update({'_id': json_item['_id']}, json_item,
upsert=True)
return item
def close_spider(self, spider):
self.client.close()
我们使用管道流将数据存储在mongodb数据库中,mongodb是一种nosql数据库,官方链接:https://docs.mongodb.com/manual/
参考资料:
http://api.mongodb.com/python/current/api/pymongo/index.html
http://wiki.jikexueyuan.com/project/mongodb/
安装:http://www.jianshu.com/p/5598f1dcbb98
下面简单的描述下mongodb的安装和使用,下载mongodb软件安装包并安装,mongodb分为服务端和客户端,mongod.exe是服务端,而mongo.exe是客户端,cmd到mongodb的bin目录下(也可以将mongod加入到环境变量),执行指令:
mongod --dbpath "d:\mongotest\mongodb\data"
后面的路径为数据存放路径,这样就开启了服务端进程
将mongo.exe的路径,加入到环境变量,然后在控制台输入mongo即可开启一个客户端进程mongo shell,mongo的基本指令参见官方文档。
在此例中,我们使用python的客户端,安装pymongo包:
pip install pymongo
用python代码实现将数据存入mongo数据库的操作如上面的代码所示。
settings:
settings.py中需要更改一些设置:
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
关闭遵守robots协议
DOWNLOAD_DELAY = 3
设置下载延迟为3秒,避免下载过快被封ip
DEFAULT_REQUEST_HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64)
AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/59.0.3071.115 Safari/537.36',
}
更改默认请求头,这里使用的是chrome浏览器的
ITEM_PIPELINES = {
'jianshu.pipelines.JianshuPipeline': 300,
}
启用pipeline
这样,基本就大功告成了,我们可以爬取@IT·互联网页面的所有博客,并存入mongo数据库。
image.png