追书神器(一)—Scrapy入门

前言

看小说是我这么多年来一直保持的习惯。《盘龙》、《斗破苍穹》、《仙逆》、《凡人修仙传》等等,陪伴了我整个学生时代。最近发现iOS上小说类app体验都很差,常常出现广告弹出、更新不及时、强制分享等状况。因而在一个下雨的晚上,我决定再也不忍受这些app,本身强撸一个追书爬虫。html

Scrapy介绍

Scrapy是python主流爬虫框架,能够很方便的经过url抓取web信息,同时与传统的requests库相比,提供了更多的工具和更高的并发。推荐从官方学习网站上学习。python

不过,你一点scrapy资料都不知道也没有关系,读完本文同样能撸出来git

Scrapy实战

在开始前,咱们须要准备好如下几个东西:github

  1. 想要爬取的小说url
  2. 环境搭建
  3. 入门级的python语法

选取网站

这里我选的是 m.book9.net/。 选这个网站是由于它有是三个优势web

  1. 更新速度比较快 (服务稳定)
  2. 页面的结构简单 (易于解析)
  3. 没有作一些防爬虫的保护 (操做简单)

接下来,找到追更小说的主页。shell

好比 辰东的《圣墟》数组

upload successful

假设如今咱们要追更的话,须要每次打开这个网站,而后点击最新章节的第一个选项条,连接到具体的小说章节。浏览器

仿造以上的步骤,我画出了这样一个流程:bash

upload successful

因此接下来,咱们只须要根据这些流程来转化成咱们的代码就行了并发

搭建工程

咱们将要搭建一个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来打开刚刚建立好的工程。

upload successful

scrapy的全部爬虫服务都集中在spiders目录下,咱们也在这里添爬虫文件novel.py

请求小说主页

upload successful
咱们打开文件,添加一些基础的配置

# 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功能查看参数

upload successful

从上图中咱们能够发现,response包含了请求的html信息。所以咱们只须要其稍加处理,截取出咱们须要的部分。

获取最新章节url

那么如何解析咱们须要的节点呢,response给咱们提供了 xpath方法,咱们只须要输入的xpath规则就能够定位到相应html标签节点。

不会xpath语法不要紧,Chrome给咱们提供了一键获取xpath地址的方法(右键->检查->copy->copy xpath),以下图:

upload successful

经过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
复制代码

展现视频

image

思考

总体写完下来,发现很难作到一份代码适用于多个站点。所以遇到在多站点抓取的需求时,为每一个站点创建一个爬虫文件会更为适合。

源码地址(据说年末点了star的年终会加倍哦)

相关文章
相关标签/搜索