使用Python自动抓取更新的小说,并发送到Instapaper上


一直比较喜欢看小说,可是自从几年前我的起点账号莫名其妙的被人盗了然后还无法找回之后就放弃了起点。 最近在用飘天文学在看,可是问题就是更新的时候没有办法像起点那样给我提醒。 所以只能时不时地用刷网页看看有没有更新。 另一点就是伦敦地铁里没有信号,像我这样每天需要一个小时通勤的人在地铁里只能每次到站的时候快速连一下wifi,上个网。 直到我遇到了Instapaper

Instapaper

Instapaper 可以把想要看的网页保存下来,稍后阅读。 对于我来说就成为了一个菜谱,教程的集散地。 经常性的看到一些让我心动的教程,我就把它们保存到Instapaper里面。 相对于Pocket,Instapaper是免费的。

用着Instapaper的时候我就在想如果能把小说自动放进来就好了,这样即使没有网络我也可以看小说。

Python 抓取小说

之前看了些爬虫的教程,感觉这个可以帮助我实现这一简单的目标。 实际上这里的东西并没有爬虫那么复杂,不需要每个链接都过一遍。 因为我使用的是飘天文学,所以网址的结构是

http://www.piaotian.com/bookinfo/小说代码.html

小说代码在novel_url这个变量里。

  • 在这里我用了pickle来储存每次抓取的结果。用来和下一次抓取的结果做比较来找出最新更新的章节网址。

  • 如果是第一次运行,代码会查看是否有url.pkl这个文件存在,如果不存在的话就把last_url这个变量设为empty list。

  • 之后就是一个简单的for loop,因为我在同时追四本小说,所以就要抓取每本小说。

  • 对比之前抓取的结果,多出来的就是最新更新的章节,把这些章节发送到instapaper里面。

  • 设定让这个程序每20分钟运行一次。

下面的代码就是实现抓取最新章节的网址:

#!/usr/bin/env python
import requests
import re
import os.path
import pickle
from bs4 import BeautifulSoup
from instapaperlib import Instapaper
from apscheduler.schedulers.blocking import BlockingScheduler

# 想要抓取的小说名和小说在飘天网网址里的代码
novel_list=["一念永恒", "道君", "带着仓库到大明", "圣墟"]
novel_url = ['7/7981','8/8491','8/8472','8/8253' ]
def fetch_novel(novel_list, novel_url):
    print('job running')
    # 检查是否存在url.pkl文件,如果不存在就把last_url设为emtpy list。 如果存在就把其中保存的内容是为last_url
    if os.path.isfile('url.pkl'):
        with open('url.pkl') as f:
            last_url = pickle.load(f)
        f.close()
    else:
        last_url=[[],[],[],[]]
    # 使用instapaper的API 登陆instapaper
    ins = Instapaper("username","password")
    ins.auth()

    url_archive = []
    for j in range(0,len(novel_list)):
        ## 检测最新章节地址
        # 小说网页
        old_url=last_url[j]
        url = 'http://www.piaotian.com/bookinfo/'+novel_url[j]+'.html'
        head = {}
        # 使用代理
        head['User-Agent'] = 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19'
        # 创建request对象
        page = requests.get(url)
        # 通过BeautifulSoup分析
        soup = BeautifulSoup(page.content,'lxml')
        # 找出最新章节的div
        soup_text = soup.find_all("a", href=re.compile(novel_url[j]), target="_blank",title=re.compile(""))
        # 保存章节的地址和章节名
        latest_url=[]
        latest_title=[]
        for i in range(0,len(soup_text)):
            latest_url.append(soup_text[i]['href'])
            latest_title.append(novel_list[j]+'---'+soup_text[i]['title'].encode('utf-8') )
        # 对比上次抓取的章节地址和这次抓取的,把新更新的章节地址发送到instapaper上
        for i in range(0,len(latest_url)):
            if latest_url[i] in old_url:
                pass;
            else:
                print(latest_url[i],latest_title[i])
                ins.add_item(latest_url[i],latest_title[i])
        old_url=latest_url
        url_archive.append(old_url)
        print(novel_list[j])
    # 把这次抓取的信息保存到url.pkl里面,以便下次抓取的时候使用
    with open('url.pkl', 'w') as f:
        pickle.dump(url_archive,f)
    f.close()
# 让上面的function每20分钟运行一次
scheduler = BlockingScheduler()
scheduler.add_job(fetch_novel, 'interval', minutes= 1, args=[novel_list, novel_url],timezone="Europe/London")
scheduler.start()

使用docker在家庭服务器上运行

然后就是在我的家庭服务器上运行这个抓取程序。 像nextcloud一样,我用docker来运行这个程序。

  • 首先新建一个文件夹,在这里命名为fetch_novel
  • 把上面的script保存为xiaoshuo.py,并且保存在fetch_novel文件夹里
  • 在这个文件夹里创建Dockerfile并将以下代码复制进去:
    FROM python:2
    RUN mkdir /usr/src/novel
    WORKDIR /usr/src/novel
    COPY . /usr/src/novel
    RUN pip install -r requirements.txt
    CMD ["python2.7", "xiaoshuo.py"]
    
  • 在同样的文件夹里创建requirements.txt 写下python代码需要的package:
    requests
    Lxml
    bs4
    BeautifulSoup
    Instapaper
    instapaperlib
    apscheduler
    
  • 最后,在这个文件夹里创建docker-compose.yml 写下以下:
    version: '2'
    services:
      novel:
        container_name: fetch_novel
        build: .
        volumes:
          - /host/folder:/usr/src/novel
        restart: always
    

    其中/host/folder 是你主机里面的文件夹,可以把docker里面的/usr/src/novel文件夹map到/host/folder。这样可以对其进行更改。

  • 最后最后,在这个文件夹下开启terminal, 在里面输入docker-compose up -d来建立并启动这个docker image

如此就可以让这个程序每20分钟查看一下有没有更新的小说章节,如果有的话就推送到自己的instapaper账号。 如果喜欢的话,可以用ifttt设置一下,在instapaper每次保存新项目的时候让ifttt发送提醒。