闲着无聊看漫画,《镇魂街》,本来想等着动漫出来再看,等了好久也没出第二季,还是看漫画吧。
有的时候是不是会出现502,而且刷新的好慢,看的好烦躁,还是把动画下载下来吧,以前还在上学的时候,有使用python写过抓数据的demo,之前的比较简单,这次的稍微有点复杂,花了点时间写出来了,没有系统的学过python,所以写的肯定有点搓,哈哈,在这里做个备份,有什么优化的地方,可以评论提出来
百度搜索“镇魂街”,第一个链接,有妖气到50集就要VIP了,我也懒得管是不是要充钱才能看,就换了下面的仆飞漫画
点进去,首先肯定是根据这个连接 http://www.pufei.net/manhua/20/ 获取整个页面的html代码
def get_content(self, url):
ua = fake_useragent.UserAgent()
headers = {
'User_Agent': ua.random}
response = requests.get(url, headers=headers)
r = response.text
a = r.encode('ISO-8859-1').decode(requests.utils.get_encodings_from_content(r)[0])
return a
为了避免会被网站拦截请求,所以在请求头改变一下参数User_Agent,也不知道管不管用,哈哈
这里使用了request和fake_useragent库,需要import一下
import fake_useragent
import requests
还需要注意的时候,获取下来的html中文会乱码,所以需要重新编码再解码,代码很容易看懂,不多解释
接着要获取章节的名称,分析一下html的格式,我使用的是bs4来解析这个页面,然后通过css选择器获取这个div,然后遍历所有的li标签,再获取a标签,就可以拿到href连接了,注意这里的连接是相对路径,需要拼上网站的域名
代码像这样
def get_page_chapter(self, url, dir_path):
content = self.get_content(url)
sel = bs4.BeautifulSoup(content, 'lxml')
div = bs4.BeautifulSoup(str(sel.select_one('.max-h200')), 'lxml')
for li in div.find_all("li"):
a_url = li.find("a")
if a_url:
url = a_url.get("href")
self.download_chapter('http://www.pufei.net' + url, a_url.get_text(), dir_path)
最最关键的来了,正常情况下,获取到章节的地址就可以获取到图片信息了,但是这个网站不是这么做的,这个网站是通过js动态的请求图片获取的,所以说单独的获取当前页面的内容是获取不到图片信息的
既然是动态的加载图片,肯定需要通过css选择器获取到图片的这个div,图片的这个div的class是viewimages,打开浏览器的调试功能,在网络那里搜索一下这个关键字看看,可以看到在view.js的这个文件加载图片的,继续找img标签的src属性
可以看到需要用到photosr这个数组的,不过初始化的代码不在这个文件中,继续全局搜索
可以看到这个变量是在下图的这个位置这里定义的,也就是进入当前章节页面就初始化了,继续搜索发现没有哪个地方是给这个变量赋值的,坑爹!!!
不过注意到下面有个packed常量,猜测可能是初始化photosr这个变量的
这么长一串的东西也不知道是啥,一开始尝试将js代码改成python来写,发现不好弄,放弃了,改用python的execjs库来调用js,将这段js全部复制下面,注意有个base64decode方法有用到,一起复制下面,因为这段代码是初始化photosr这个变量的,所以最终结果需要返回这个变量
var photosr = new Array();
function base64decode(str) {
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var base64DecodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
var c1, c2, c3, c4;
var i, len, out;
len = str.length;
i = 0;
out = "";
while (i < len) {
do {
c1 = base64DecodeChars[str.charCodeAt(i++) & 255]
} while (i < len && c1 == -1);
if (c1 == -1) {
break
}
do {
c2 = base64DecodeChars[str.charCodeAt(i++) & 255]
} while (i < len && c2 == -1);
if (c2 == -1) {
break
}
out += String.fromCharCode((c1 << 2) | ((c2 & 48) >> 4));
do {
c3 = str.charCodeAt(i++) & 255;
if (c3 == 61) {
return out
}
c3 = base64DecodeChars[c3]
} while (i < len && c3 == -1);
if (c3 == -1) {
break
}
out += String.fromCharCode(((c2 & 15) << 4) | ((c3 & 60) >> 2));
do {
c4 = str.charCodeAt(i++) & 255;
if (c4 == 61) {
return out
}
c4 = base64DecodeChars[c4]
} while (i < len && c4 == -1);
if (c4 == -1) {
break
}
out += String.fromCharCode(((c3 & 3) << 6) | c4)
}
return out
}
function f(data) {
eval(eval(base64decode(data).slice(4)));
return photosr
}
引入execjs库,执行代码如下,获取到这个章节的所有漫画的连接,这里获取到的一样是相对地址,下面使用的时候需要拼上域名
import execjs
def get_js(self):
f = open("base64decode.js", 'r', encoding='utf-8')
line = f.readline()
html_str = ''
while line:
html_str = html_str + line
line = f.readline()
return html_str
def base_64_decode(self, data):
js_str = self.get_js()
ctx = execjs.compile(js_str)
return ctx.call('f', data)
由于每个章节的packed肯定是不一样的,所有需要使用正则表达式截取这个变量,注意需要导入re库,代码像这样
search_obj = re.findall(r'packed="(.+)";eval', content, re.S)
已经获取图片的地址了,接下来就比较简单了,只需要下载到本地就好了,代码如下
def get_image(self, img_urls):
response = requests.get(img_urls)
if response.status_code == 200:
return response.content
def download_chapter(self, url, chapter_name, dir_path):
content = self.get_content(url)
search_obj = re.findall(r'packed="(.+)";eval', content, re.S)
count = 1
for url2 in self.base_64_decode(search_obj[0]):
if isinstance(url2, str):
if url2:
image_path = dir_path + '/' + chapter_name + '/P-%s.jpg' % count
if not os.path.exists(dir_path + '/' + chapter_name):
os.makedirs(dir_path + '/' + chapter_name)
if not os.path.exists(image_path):
image = self.get_image("http://res.img.pufei.net/" + url2)
if image:
with open(image_path, 'wb') as f:
f.write(image)
count += 1
为了避免图片乱序,所有将图片的名称改为P-xx,这样漫画的顺序就不会乱了
调用的主函数如下:
from DownloadPage import *
url = "http://www.pufei.net/manhua/20/"
save_path = "F:/dongman"
downloadPage = DownloadPage()
content = downloadPage.get_page_chapter(url, save_path)
效果如下:
python版本用的是3.7
代码github地址:https://github.com/justdrinkWater/downloadCartoon