关于用python爬虫白嫖漫画这档子事
文章目录
关于用python爬虫白嫖漫画这档子事前言操作环境网页分析1. 漫画主页2. 获取章节链接列表3. 获取章节图片4. 小结
编写代码1. 准备2. 获取章节链接列表3. 获取图片列表4. 图片下载
运行完整代码
前言
笔者平时喜欢看漫画,用得比较多的漫画APP是txdm和kkmh,尽管都开了会员,靠着平时做任务和签到得到的点卷凑活度日,但依旧无法满足,尤其是发现一些完结的神作,整本下来也得几百,对于一个学生来说,还是很肉疼的,于是萌生用爬虫来白嫖的想法。
网上教程很多,也包括爬取txdm的,但它是无法爬取付费部分的,除非买下付费部分,这就与我的初衷背道相驰了。所以我的目标只能转向同样是爬虫爬来的漫画网站,这些网站有几个共同点:广告多,阅读体验差,一般坚持不了一年就没了。 现在是2022年11月,我找到的一个几乎无反爬,下载速度快的漫画网站m.imitui.com,如果你看到这篇文章时,这个链接是无效的,或者在这个网站上没有找到你想看的漫画,也没必要往下看了。
操作环境
Python: 3.8
第三方库:requests, selenium
网页分析
1. 漫画主页
搜索漫画名,进入漫画主页,观察导航栏URL,可以发现是有规律的,即weburl+comic_name,这里comic_name作为参数传给程序看到以下折叠章节列表
2. 获取章节链接列表
按F12,检查章节元素
右键点击元素,复制选项里得到xpath路径为://*[@id="chapter-list-1"]/li[2]/a,即所有的章节链接统一表示为//*[@id="chapter-list-1"]/li/a章节链接地址就在的href属性中。
3. 获取章节图片
进入任意一个章节,检查图片元素,发现分为两部分:封面和内容封面图片如下,右击,在复制选项中得到对象xpath路径://*[@id="image"]
内容图片如下,右击,在复制选项中得到对象xpath://*[@id="scroll-item-1"]/img
图片的url就在的src属性中。
4. 小结
总体思路:漫画页面->章节链接列表->进入章节下载图片注意:需要在请求头header中加入refer,表明请求来自于哪儿
编写代码
1. 准备
import sys
import time
import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
import threading
# 漫画在本地的存储路径,%s用来替换文件夹名
DIRBASE = 'D:/Picture/Comics/%s/'
# 无需启动浏览器UI运行
chromeOptions = Options()
chromeOptions.add_argument('--headless')
# 请求头
HEADER = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/107.0.0.0 Safari/537.36',
'Referer': 'https://m.imitui.com/'
}
def main(comic_name, dir_name, restart=0):
"""
:param comic_name: 从漫画主页的url中提取的漫画名
:param dir_name: 自己命名的存储文件夹
:param restart: 各种原因导致程序结束,可以设置重启的章节数
"""
# 创建存储文件夹
global DIR, URL
DIR = DIRBASE % dir_name
if not os.path.exists(DIR):
os.mkdir(DIR)
# 需要爬取的漫画主页url
URL = 'https://m.imitui.com/manhua/%s' % comic_name
# 爬取正式开始
run(restart)
if __name__ == '__main__':
# 在命令行中这样调用 python crawler.py comic_name dir_name
# 若中断过,则这样: python crawler.py comic_name dir_name restart
arg1 = sys.argv[1]
arg2 = sys.argv[2]
if len(sys.argv) > 3:
arg3 = sys.argv[3]
main(arg1, arg2, int(arg3))
else:
main(arg1, arg2)
2. 获取章节链接列表
def run(restart):
# 1. 初始化浏览器驱动
driver = webdriver.Chrome(options=chromeOptions)
# 2. 获取章节列表
driver.get(URL)
time.sleep(2)
chapter_list = driver.find_elements('xpath', '//*[@id="chapter-list-1"]/li/a')
# 除去预告
chapter_list.pop()
# 逆序,从低序号章节开始
chapter_list.reverse()
# 3. 访问章节页面进行操作
for j in range(restart, len(chapter_list)):
# 进入对应章节页面
print('进入章节%d: ' % j + chapter_list[j].get_attribute('href'))
# 创建章节文件夹
directory = DIR + '%03d/' % j
if os.path.exists(directory):
continue
os.mkdir(DIR + '%03d/' % j)
# 开始下载章节
get_chapter(DIR + '%03d/' % j, chapter_list[j].get_attribute('href'))
# time.sleep(1)
# 6. 退出
driver.quit()
3. 获取图片列表
def get_chapter(directory, url):
# 1. 初始化浏览器驱动
driver = webdriver.Chrome(options=chromeOptions)
# 2. 访问章节页面
driver.get(url)
# 3. 提取内容图片列表
img_list = driver.find_elements('xpath', '//*[@id="scroll-image"]/div/img')
# 4. 插入封面图片
img_list.insert(0, driver.find_element('xpath', '//*[@id="image"]'))
# 这里采用多线程下载,即将一个章节的图片分成三份下载
pos14 = int(len(img_list)/4)
pos24 = int(len(img_list)/4*2)
pos34 = int(len(img_list)/4*3)
# ImageDownloader类的实现在后面
# 其他线程
thread1 = ImageDownloader(img_list, directory, pos14, pos24)
thread2 = ImageDownloader(img_list, directory, pos24, pos34)
thread3 = ImageDownloader(img_list, directory, pos34, len(img_list))
thread1.start()
thread2.start()
thread3.start()
# 主线程
getImage(img_list, directory, 0, pos14)
4. 图片下载
class ImageDownloader(threading.Thread):
"""
下载图片的线程类
"""
def __init__(self, img_list, directory, start, end):
self.img_list = img_list
self.directory = directory
self.begin = start
self.end = end
super().__init__()
def run(self):
getImage(self.img_list, self.directory, self.begin, self.end)
def getImage(img_list, directory, start, end):
for i in range(start, end):
# 4.1 获取图片url
img_url = img_list[i].get_attribute('data-src')
if img_url is None:
img_url = img_list[i].get_attribute('src')
# 4.2 发送请求,获取数据
img_data = requests.get(img_url, headers=HEADER).content
# 4.3 保存数据
with open('%s%03d.jpg' % (directory, i), mode='wb') as image:
image.write(img_data)
运行
在当前项目文件夹中:python .\IMIComic.py nitianxieshen xieshen
完整代码
import sys
import time
import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
import threading
DIRBASE = 'D:/Picture/Comics/%s/'
chromeOptions = Options()
chromeOptions.add_argument('--headless')
HEADER = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/107.0.0.0 Safari/537.36',
'Referer': 'https://m.imitui.com/'
}
DIR = ''
URL = ''
def main(comic_name, dir_name, restart=0):
"""
:param comic_name: 从漫画主页的url中提取的漫画名
:param dir_name: 自己命名的存储文件夹
:param restart: 各种原因导致程序结束,可以设置重启的章节数
"""
global DIR, URL
DIR = DIRBASE % dir_name
if not os.path.exists(DIR):
os.mkdir(DIR)
URL = 'https://m.imitui.com/manhua/%s' % comic_name
run(restart)
def run(restart):
# 1. 初始化浏览器驱动
driver = webdriver.Chrome(options=chromeOptions)
# 2. 获取章节列表
driver.get(URL)
time.sleep(2)
chapter_list = driver.find_elements('xpath', '//*[@id="chapter-list-1"]/li/a')
chapter_list.pop()
chapter_list.reverse()
# 3. 访问章节页面进行操作
for j in range(restart, len(chapter_list)):
# 进入对应章节页面
print('进入章节%d: ' % j + chapter_list[j].get_attribute('href'))
directory = DIR + '%03d/' % j
if os.path.exists(directory):
continue
os.mkdir(DIR + '%03d/' % j)
get_chapter(DIR + '%03d/' % j, chapter_list[j].get_attribute('href'))
# time.sleep(1)
# 6. 退出
driver.quit()
def get_chapter(directory, url):
# 1. 初始化浏览器驱动
driver = webdriver.Chrome(options=chromeOptions)
# 2. 访问章节页面
driver.get(url)
# 3. 提取图片列表
img_list = driver.find_elements('xpath', '//*[@id="scroll-image"]/div/img')
img_list.insert(0, driver.find_element('xpath', '//*[@id="image"]'))
pos14 = int(len(img_list)/4)
pos24 = int(len(img_list)/4*2)
pos34 = int(len(img_list)/4*3)
thread1 = ImageDownloader(img_list, directory, pos14, pos24)
thread2 = ImageDownloader(img_list, directory, pos24, pos34)
thread3 = ImageDownloader(img_list, directory, pos34, len(img_list))
thread1.start()
thread2.start()
thread3.start()
getImage(img_list, directory, 0, pos14)
class ImageDownloader(threading.Thread):
"""
下载图片的线程类
"""
def __init__(self, img_list, directory, start, end):
self.img_list = img_list
self.directory = directory
self.begin = start
self.end = end
super().__init__()
def run(self):
getImage(self.img_list, self.directory, self.begin, self.end)
def getImage(img_list, directory, start, end):
for i in range(start, end):
# 4.1 获取图片url
img_url = img_list[i].get_attribute('data-src')
if img_url is None:
img_url = img_list[i].get_attribute('src')
# 4.2 发送请求,获取数据
img_data = requests.get(img_url, headers=HEADER).content
# 4.3 保存数据
with open('%s%03d.jpg' % (directory, i), mode='wb') as image:
image.write(img_data)
if __name__ == '__main__':
arg1 = sys.argv[1]
arg2 = sys.argv[2]
if len(sys.argv) > 3:
arg3 = sys.argv[3]
main(arg1, arg2, int(arg3))
else:
main(arg1, arg2)
推荐阅读
发表评论