[水]用python写一个爬虫,多线程自动下载本子并打成压缩包quq

前言

前两天在群里聊天无意之间被人安利了一个看本子的网站,最近正好又准备在自己电脑上拿电子书管理软件把本子什么的整理下(当然,看到画风可爱的新本子还是会下载了再说的quq)

但是被推荐的那个网站的下载功能不是很尽如人意,提供的种子连接性也不是很好,考虑到咱喜欢的本子也不多,但是又懒得一本本去单独找其他下载源,于是决定直接写个脚本爬下来

使用爬虫爬取资源站的行为好孩子不要模仿quq

不过在此之前咱也没正经写过爬虫就是了。。首先观察了一下那个网站,缩略图和实际图片的url规则基本一致,实际请求的链接把直链作为请求的一部分被传入了另一个站点,姑且推测是cdn或者其他什么。。。但是经过测试通过原本的完整链接再爬取的话,有一定概率会被400,但是直接访问后面的直链就没有这个问题。。。。所以决定直接使用直链下载

事前准备&环境介绍

原本是准备直接python走到底的,但是前几天看到b站上有个神奇的专栏,讲如何用C写一个b站粉丝计数器的,结果实现过程是直接再终端执行curl去抓b站的api的。。。于是抱着玩梗的心态,这个爬虫的下载的部分就用wget完成好了quq(简单来说就是都已经import requests了,但就是不用quq)

环境大概写下来就是Debian 10+Python3,使用到的python库有:
re (拿来正则)
requests(获取缩略图的链接)
bs4(拿来按标签找网页里的元素)
os(拿来执行wget和zip之类的系统里的命令)
事后还手动引用了_thread。。。姑且明面上整了个多线程?

不过毕竟是本子站。。。又是资源站本文中就不使用真实url了。。。毕竟咱也不推荐或鼓励大家使用爬虫下载图站的资源(找图这件事最快乐的事情应该就是在无数不喜欢的图中找到自己喜欢的图),如果可能的话也希望大家如果爬取资源的的话能够尽量缓慢些爬取呢(毕竟有些资源站就是被无脑爬图爬死的。。。

通过那个本子站的网页得知的信息

缩略图的原始链接大概长这样:https://H-Books.org/?search=https://t.example.com/time/stamp/and/pic/IDt.jpg
原图的原始链接大概长这样:https://H-Books.org/?search=https://i.example.com/time/stamp/and/pic/ID.jpg

当然,根据前文咱的描述也可以知道。。。search=后面紧跟着的其实就是直链,所以之后就直接用后面的直链了。。。

看本子的页面的html大概长这样

<html>
    <head>
        <title>本子名称</title>
    </head>
    <body>
        <a class="gallerythumb" href="#">
            <img data-src="https://H-Books.org/?search=https://t.example.com/time/stamp/and/pic/1t.jpg">
        </a>
        <a class="gallerythumb" href="#">以下省略更多页</a>
    </body>
</html> 然后就是经过测试发现直链本身没设置防盗链,也不对UA进行任何筛选。。。几乎可以说写成爬虫也是爬虫里最简单的那种。

代码和简单介绍

完整版的代码折叠在这里了
#!/usr/bin/python3
from bs4 import BeautifulSoup as bs
import requests as req
import _thread as tr
import os,re

def mp(tn, msg):
    print("线程"+tn+":"+msg)

def get_links(tn, url):
    mp(tn, url)
    raw = req.get(url)
    res = bs(raw.text)
    name = re.sub(r'[\/\\\:\*\?\"\<\>\|]', ' ', res.title.string.split('»')[0])
    mp(tn, name)
    pl = []
    for i in res('a', class_='gallerythumb'):
        pl.append(i.img.get('data-src').split('=')
                  [1].replace('t.', 'i.', 1).replace('t.', '.'))
    indir = pl[0].split('/')[-2]
    os.makedirs(indir)
    dlarc(name, pl, indir, tn)
    os.removedirs(indir)
    return 0

def dlarc(name, pl, indir, tn):
    fl = []
    for i in pl:
        fl.append(i.split('/')[-1])
        # mp(tn,i)
        os.system('wget -c \'{}\' -O \'./{}/{}\' 2>/dev/null'.format(i, indir, i.split('/')[-1]))
    mp(tn, pl[0])
    for i in fl:
        os.system(
            'zip -gmrj \'{}.zip\' \'./{}/{}\' | grep stored'.format(name, indir, i))

while 1:
    org = input('请输入URL: ')
    try:
        tr.start_new_thread(get_link, (org.split('/')[-2], org))
    except:
        print ("Error: 无法启动线程")

首先定义了一个用来获取图片链接的函数,需要传入url,使用requests获取传入的url后把网页丢给bs4,然后通过bs4从网页找到本子的名称,缩略图对应的链接,并按照上面的规则把缩略图url修改成原图url(具体实现方法可以直接从bs4的文档里复制粘贴,这一切都要感谢美丽的汤可以给咱省下无数的时间用来偷懒quq),然后对本子名称进行简单检查,以防止压缩后文件中出现Windows下不能使用的字符。

然后定义了下载和压缩的函数,然后简单的把上一个函数整理好的url逐一丢给wget,下载完成后再把文件全部丢给zip。。。大概也没什么可说的

最后为了好看,增加了一个请求用户输入的欢迎语。。。

最初咱的爬虫就到此为止了,不过由于直接直链下载,速度堪忧,通过Google找到了可以让速度飞升的好办法quq。。。多线程!
(只不过python的多线程据说是样子货。。。不过对于下载这种纯io的事情,能用就行quq)

因为咱也是第一次用,所以并不知道实际上应该怎么实现,但是好像只要在调用函数的事后通过_thread来调用就好了(不过根据实际测试结果,欢迎语的显示会变得不太对就是了)

总结

找一堆喜欢的本子偶尔爬一爬也还挺有意思的quq。。。

不过也真的是无聊到一种地步才会觉得爬图站会很快乐吧quq。。。

本文与其说是教程。。。倒不如说是实在闲的没事干了随便水一水证明自己还有坚持咕咕咕罢了quq。。。

点赞
  1. FH云彩说道:
    Google Chrome Windows 10