看小说是我这么多年来一直保持的习惯。《盘龙》、《斗破苍穹》、《仙逆》、《凡人修仙传》等等,陪伴了我整个学生时代。最近发现iOS上小说类app体验都很差,常常出现广告弹出、更新不及时、强制分享等状况。因而在一个下雨的晚上,我决定再也不忍受这些app,本身强撸一个追书爬虫。html
Scrapy是python主流爬虫框架,能够很方便的经过url抓取web信息,同时与传统的requests库相比,提供了更多的工具和更高的并发。推荐从官方学习网站上学习。python
不过,你一点scrapy资料都不知道也没有关系,读完本文同样能撸出来git
在开始前,咱们须要准备好如下几个东西:github
这里我选的是 m.book9.net/。 选这个网站是由于它有是三个优势web
接下来,找到追更小说的主页。shell
好比 辰东的《圣墟》数组
假设如今咱们要追更的话,须要每次打开这个网站,而后点击最新章节的第一个选项条,连接到具体的小说章节。浏览器
仿造以上的步骤,我画出了这样一个流程:bash
因此接下来,咱们只须要根据这些流程来转化成咱们的代码就行了并发
咱们将要搭建一个Scrapy壳工程,在这以前要先确保本身安装了python的环境。框架自身兼容二、3版本,因此不须要担忧版本的差别。
我本地的环境是python3,因此可能会和2有细微的差别操做。
1.安装Scrapy
> pip3 install scrapy
复制代码
2.建立爬虫工程,将其命名为NovelCrawler
> scrapy startproject NovelCrawler
复制代码
3. 建立一个基于 url 的爬虫服务
> scrapy genspider novel m.book9.net
复制代码
以上就是基本的工程建立过程,执行完毕以后就可使用
> scrapy crawl novel
复制代码
命令去开启爬虫服务。不过当前咱们的爬虫尚未实现任何的规则,因此即便执行了命令也不会作任何事,因此咱们须要在工程中添加一些爬虫规则。
接下来咱们用Pycharm来打开刚刚建立好的工程。
scrapy的全部爬虫服务都集中在spiders目录下,咱们也在这里添爬虫文件novel.py
# encoding:utf-8
import scrapy
class NovelSpider(scrapy.Spider):
#配置服务名称,与上文建立服务的名称相同
name = 'novel'
#容许访问的域,与上文建立服务的名称相同
allowed_domains = ['m.book9.net']
#发起请求的url,《圣墟》小说主页
start_urls = ['https://m.book9.net/wapbook/10.html']
#默认的请求成功的回调函数
def parse(self, response):
pass
复制代码
上面的代码中,parse函数的入参数response对象里面有什么参数对咱们来讲是未知的,这也是初学python很头疼的地方。这里给你们提供一个方法:用Pycharm的debug功能查看参数
从上图中咱们能够发现,response包含了请求的html信息。所以咱们只须要其稍加处理,截取出咱们须要的部分。
那么如何解析咱们须要的节点呢,response给咱们提供了 xpath方法,咱们只须要输入的xpath规则就能够定位到相应html标签节点。
不会xpath语法不要紧,Chrome给咱们提供了一键获取xpath地址的方法(右键->检查->copy->copy xpath),以下图:
经过xpath,咱们能够从这个页面获取到最新章节的地址
# encoding:utf-8
import scrapy
class NovelSpider(scrapy.Spider):
name = 'novel'
allowed_domains = ['m.book9.net']
start_urls = ['https://m.book9.net/wapbook/10.html']
def parse(self, response):
#指定的<a>标签的跳转连接
context = response.xpath('/html/body/div[3]/div[2]/p[1]/a/@href')
#提取数组的第一个结果 即最新章节的url
url = context.extract_first()
print(url)
pass
复制代码
有了连接以后,咱们就能够跳转到下一个页面。而response也提供了follow方法,便于咱们在站内进行短链的跳转。
# encoding:utf-8
import scrapy
class NovelSpider(scrapy.Spider):
name = 'novel'
allowed_domains = ['m.book9.net']
start_urls = ['https://m.book9.net/wapbook/10.html']
def parse(self, response):
context = response.xpath('/html/body/div[3]/div[2]/p[1]/a/@href')
url = context.extract_first()
#获取短链后继续请求,并将结果返回指定的回调
yield response.follow(url=url, callback=self.parse_article)
#自定义回调方法
def parse_article(self,response):
#这里的response 就是咱们具体的文章页
print(response)
pass
复制代码
(如对代码中关键字yield感到疑惑的请点击传送门)
有了文章的页面,咱们只须要对他的html进行解析。这部份内容过于面向细节。只适用于这个网站,所以我不过多进行赘述。附上注释代码:
# encoding:utf-8
import re
import os
import scrapy
class NovelSpider(scrapy.Spider):
name = 'novel'
allowed_domains = ['m.book9.net']
start_urls = ['https://m.book9.net/wapbook/10.html']
def parse(self, response):
# 指定的<a>标签的跳转连接
context = response.xpath('/html/body/div[3]/div[2]/p[1]/a/@href')
#获取短链后继续请求,并将结果返回指定的回调
url = context.extract_first()
yield response.follow(url=url, callback=self.parse_article)
def parse_article(self, response):
#获取文章的标题
title = self.generate_title(response)
#构建文章的html
html = self.build_article_html(title, response)
#将章节html存至本地
self.save_file(title + ".html", html)
#用自带的浏览器打开本地html
os.system("open " + title.replace(" ", "\ ") + ".html")
pass
@staticmethod
def build_article_html(title, response):
#获取文章内容
context = response.xpath('//*[@id="chaptercontent"]').extract_first()
#过略文章中<a> 标签跳转内容
re_c = re.compile('<\s*a[^>]*>[^<]*<\s*/\s*a\s*>')
article = re_c.sub("", context)
#拼接文章html
html = '<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><div align="center" style="width:100%;text-alight:center"><b><font size="5">' \
+ title + '</font></b></div>' + article + "</html>"
return html
@staticmethod
def generate_title(response):
title = response.xpath('//*[@id="read"]/div[1]/text()').extract()
return "".join(title).strip()
@staticmethod
def save_file(file_name, context):
fh = open(file_name, 'wb')
fh.write(context.encode(encoding="utf-8"))
fh.close()
pass
复制代码
如今咱们可在再当前目录下运行如下命令:
> scrapy crawl novel
复制代码
总体写完下来,发现很难作到一份代码适用于多个站点。所以遇到在多站点抓取的需求时,为每一个站点创建一个爬虫文件会更为适合。
源码地址(据说年末点了star的年终会加倍哦)