python爬取 XKCD 中文站,包含多线程

前些日子发现了一个xkcd的中文站,想把它们都爬下来。

URL:https://xkcd.in/

这里先给大家欣赏一幅:

(图片来自:你最喜欢 xkcd 的哪一张? - 知乎 (zhihu.com)

废话不多说,我们现在就开始吧。

一、单线程下载

1、下载单页图片

我们先下最新的一张:

右键点击图片,打开检查:

发现图片存在class为comic-body的div中。

事实上,我们可以打开页面源代码,发现……

 

图片存在第一个img标签中。我们可以编写代码:

import requests, os, bs4, urllib
url = 'https://xkcd.in/'
os.makedirs('xkcd',exist_ok = True)
res = requests.get(url)
res.encoding = 'utf-8'
soup = bs4.BeautifulSoup(res.text,'html.parser')
img_tag = soup.img
print(img_tag)
url = 'https://xkcd.in' + img_tag.get('src')
print('url:',url)
urllib.request.urlretrieve(url,'./xkcd/' + img_tag.get('alt') + '.jpg')

下载完成!

2、获取下一个页面 

打开开发者模式,发现下一篇的链接存在 class 为 nextLink 的 a 标签里。

这很简单,只需要这样获取:

url = 'https://xkcd.in/' + soup.find('div',class_ = "nextLink").find('a').get('href')

3、整合

把代码整合起来,就可以下载全站漫画了:

import requests, os, bs4, urllib, time
url = 'https://xkcd.in'
os.makedirs('xkcd',exist_ok = True)
while True:
    res = requests.get(url)
    res.encoding = 'utf-8'
    soup = bs4.BeautifulSoup(res.text,'html.parser')
    img_tag = soup.img
    img_url = 'https://xkcd.in' + img_tag.get('src')
    print('正在下载:',img_url)
    urllib.request.urlretrieve(img_url,'./xkcd/' + img_tag.get('alt') + '.jpg')
    if 'id=1' == url[-4:]:    #最小id是1
        break
    url = 'https://xkcd.in/' + soup.find('div',class_ = "nextLink").find('a').get('href')
input('下载完成')

二、多线程下载

对于多线程,我知道一个很简单的库 —— multitasking 库。

只需要用 pip 安装即可:

pip install multitasking

使用方式:

import time
def main():
    time.sleep(1)
start = time.time()
for i in range(5):
    main()
end = time.time()
print(end - start)

#输出:5.00570011138916

这段代码要5秒执行。

现在我们用多线程执行:

import time, multitasking

@multitasking.task
def main():
    time.sleep(1)
start = time.time()
for i in range(5):
    main()
multitasking.wait_for_tasks()    # 等待全部线程执行完毕
end = time.time()
print(end - start)

# 输出:1.002472162246704

由于用多线程执行,所以时间少很多。

改编

我们可以建立多个线程,每个线程下载 50 个页面。

我们先编写一个分块函数:

#参考自:https://zhuanlan.zhihu.com/p/369531344

def split_(start, end, step):
    # 分多块
    parts = [(start, min(start+step, end))
             for start in range(0, end, step)]
    return parts

再改编一下下载程序:

def d(start_id,end_id):
    for id in range(start_id,end_id):
        print(id,end = '')
        url = 'https://xkcd.in/comic?lg=cn&id='+str(id)
        res = requests.get(url)
        res.encoding = 'utf-8'
        res.raise_for_status()   # 返回请求的状态
        soup = bs4.BeautifulSoup(res.text,'html.parser')
        comicele = soup.find('div',class_ = "comic-body")
        if comicele == None:
            print(',无图片')
            continue
        comicele = comicele.find_all('img')[0]
        #print(comicele)
        if comicele == []:
            print('图片未找到')
        else:
            comicurl = 'https://xkcd.in/' + comicele.get('src')
            #res = requests.get(comicurl)
            name = soup.find_all('h1')[1].text.replace(' ',"").replace('\r\n',"").replace('\\',"").replace(r"/","").replace(r"/","").replace(':',"").replace(":","").replace("*","").replace('''"''',"").replace('<',"").replace('>',"").replace('|',"")
            print('正在下载:',"D:\\python\\漫画爬虫\\xkcd_2\\%s.png"%(name))
            urllib.request.urlretrieve(comicurl,"D:\\python\\漫画爬虫\\xkcd_2\\%s.png"%(name))    # urllib.request.urlretrieve函数下载文件。

整合全部代码:

import requests,os,bs4,urllib,multitasking
from time import sleep
import signal
signal.signal(signal.SIGINT, multitasking.killall)          # ctrl + c 一次终止已开启的全部线程

@multitasking.task
def d(start_id,end_id):
    for id in range(start_id,end_id):
        print(id,end = '')
        url = 'https://xkcd.in/comic?lg=cn&id='+str(id)
        res = requests.get(url)
        res.encoding = 'utf-8'
        res.raise_for_status()   # 返回请求的状态
        soup = bs4.BeautifulSoup(res.text,'html.parser')
        comicele = soup.find('div',class_ = "comic-body")
        if comicele == None:
            print(',无图片')
            continue
        comicele = comicele.find_all('img')[0]
        #print(comicele)
        if comicele == []:
            print('图片未找到')
        else:
            comicurl = 'https://xkcd.in/' + comicele.get('src')
            #res = requests.get(comicurl)
            name = img_tag.get('alt')
            print('正在下载:',"D:\\python\\漫画爬虫\\xkcd_2\\%s.png"%(name))
            urllib.request.urlretrieve(comicurl,"D:\\python\\漫画爬虫\\xkcd_2\\%s.png"%(name))    # urllib.request.urlretrieve函数下载文件。

def get_end_id():
    return int(bs4.BeautifulSoup(requests.get('https://xkcd.in/').text,'html.parser').find('div',class_ = "nextLink").find('a').get('href').split('=')[-1]) + 1

def split_(start, end, step):
    # 分多块
    parts = [(start, min(start+step, end))
             for start in range(0, end, step)]
    return parts
s = split_(1,get_end_id(),50)
for i in s:
    if not i == s[-1]:
        d(i[0],i[1])
    else:
        d(i[0],i[1] + 1)
    sleep(5)

multitasking.wait_for_tasks()
input('下载完成')

运行结果:

0,无图片
1正在下载: 桶 - 1.png
2正在下载: “小”树(草图).png
50正在下载: Penny Arcade.png
3正在下载: 岛(草图).png
51正在下载: 疟疾.png
524100正在下载: 秘密世界.png
正在下载: 风景(草图).png
正在下载: 激光瞄准镜.png
正在下载: 爱好.png
10254150正在下载: 回到未来.png
正在下载: 科学.png
,无图片
1516,无图片
152正在下载: 冷幽默.png
55103,无图片
153正在下载: 无用功.png
正在下载: 道德相对论.png
56,无图片
1547104正在下载: 解药(治疗乐队).png
正在下载: 睡觉的女孩(素描-高二西班牙语课).png
,无图片
155,无图片

输出很乱,因为有很多线程来输出。不过下得很快,一下子就下完了。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值