用Python爬E站本

一、前言

参考并改进自 OverJerry 大佬的 教你怎么用Python爬取E站的本子_OverJerry

本文为技术学习记录,不提供访问无存在网站的任何方法,也不包含不和谐内容。

环境:

  • Python版本为从Win10应用商店安装的Python3.7.5,大概若无已安装版本,cmd输入python就会自动打开商店页面吧。不用设置PATH,但无法使用 py 命令。安装的位置在 C:\Users\<用户名>\AppData\Local\Microsoft\WindowsApps\,pip安装的模块位置大概在 C:\users\<用户名>\appdata\local\packages\
  • 编辑器为VSCode,使用推荐的Python插件
  • 语法检查工具flake8python -m pip install flake8
  • 格式化工具autopep8python -m pip install autopep8

依赖:

  • BeautifulSoup4python -m pip install BeautifulSoup4
  • requestspython -m pip install requests
  • lxmlpip install lxml

二、改进内容

  1. 支持分页下载;
  2. 允许一次输入多条链接,方便批量执行;
  3. 文件名使用id+序号的方式,方便排序;
  4. 允许对同名文件跳过;
  5. 对于某些图片不稳定导致卡死问题,做了请求超时处理,允许设置超时时长和最大重新请求次数,可以超时时间短但重发次数多,或者时间长但次数少;
  6. 对于用本名创建文件夹可能存在的名称有不合法字符问题,允许检查并替换字符;
  7. 对于站点某些本的内容不和谐提示:在cookie中添加nw=1,避免重定向导致错误;
  8. 那啥代理池没有用,原先以为卡住是被反爬虫了,原来只是单纯下载卡住了,网上扒来的方法似乎也只会报错。
  9. 想到但没做的,添加传入参数,方便批处理。

三、最终代码

  1. # -*- coding: utf-8 -*-
  2. # ehentai本子爬取,学习from:https://blog.csdn.net/weixin_41732074/article/details/87287726
  3. import requests
  4. import os
  5. import re
  6. import time
  7. from bs4 import BeautifulSoup
  8. # import random
  9. # import multiprocessing
  10. # 默认请求头
  11. headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
  12. 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
  13. 'cookie': 'nw=1', # 处理是否查看不宜内容的检查,需要写入cookie,不能用cookies直接写。
  14. 'Upgrade-Insecure-Requests': '1', # 用于从http到https转换允许通知给服务器
  15. 'DNT': '1'} # 禁止追踪
  16. rootdir = 'E:/MyGallery/comic/'
  17. overwrite = False # 当文件名存在时是否覆盖重写
  18. replacechar = '_' # 用于替换不当文件名的字符
  19. conndelay = 5 # 连接服务器最大秒数
  20. readdelay = 30 # 读取最大秒数
  21. maxretry = 2 # 下载单图失败时重试次数
  22. ip_list = [] # 代理ip池
  23. # def get_ip_list(url, headers): # 从匿名ip提供网站获取ip列表
  24. # web_data = requests.get(url, headers=headers)
  25. # soup = BeautifulSoup(web_data.text, 'lxml')
  26. # ips = soup.find_all('tr')
  27. # ip_list = []
  28. # for i in range(1, len(ips)):
  29. # ip_info = ips[i]
  30. # tds = ip_info.find_all('td')
  31. # ip_list.append(tds[1].text + ':' + tds[2].text)
  32. # return ip_list
  33. # def get_random_ip(ip_list): # 生成随机ip加端口号
  34. # proxy_list = []
  35. # for ip in ip_list:
  36. # proxy_list.append('http://' + ip)
  37. # proxy_ip = random.choice(proxy_list)
  38. # proxies = {'http': proxy_ip}
  39. # return proxies
  40. # def init_proxies(): # 初始化随机代理
  41. # url = 'http://www.xicidaili.com/nn/'
  42. # headers = {
  43. # 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36'
  44. # }
  45. # global ip_list
  46. # ip_list = get_ip_list(url, headers=headers)
  47. # # proxies = get_random_ip(ip_list)
  48. # # print(proxies)
  49. def saveFile(url, path): # 保存文件
  50. # print('目标链接: ' + url)
  51. # 代理, 超时 , proxies=get_random_ip(ip_list), timeout=(180, 3000)
  52. response = requests.get(url, headers=headers,
  53. timeout=(conndelay, readdelay))
  54. with open(path, 'wb') as f: # 只写二进制文件,存在则重写,不存在则创建
  55. f.write(response.content)
  56. f.flush()
  57. def getPicUrl(url): # 获取图片源
  58. site_2 = requests.get(url, headers=headers)
  59. content_2 = site_2.text
  60. soup_2 = BeautifulSoup(content_2, 'lxml')
  61. imgs = soup_2.find_all(id="img") # 图片的id正是img
  62. for img in imgs:
  63. picSrc = img['src']
  64. return picSrc
  65. def getPicList(url): # 获取图片分页
  66. site = requests.get(url, headers=headers)
  67. content = site.text
  68. soup = BeautifulSoup(content, 'lxml')
  69. # 获取当前分页所有gdtm类,gdtm是eh的默认小缩略图类,gdtl是eh的大缩略图类;find_all()返回一个包含元素的列表
  70. divs = soup.find_all(class_='gdtm')
  71. imgcount = 0 # 图片计数器
  72. for div in divs:
  73. imgcount = imgcount + 1
  74. print('||共 %d 张图,开始下载...' % (imgcount))
  75. title = re.sub(r'[\\/:*?"<>|\r\n]', replacechar, soup.h1.get_text())
  76. imgnum = 0
  77. i = 0
  78. for div in divs:
  79. picUrl = div.a.get('href')
  80. picAlt = div.a.img.get('alt')
  81. # 获取链接最右边一段,形如<漫画id-图片序号>,因图片序号前确少0可能导致排序问题,使用alt拼接
  82. picName = picUrl.rpartition('/')[2].rpartition('-')[0] + '-' + picAlt
  83. imgnum = imgnum + 1
  84. print('>> Saving:' + picName + '.jpg')
  85. picPath = '%s%s/%s.jpg' % (rootdir, title, picName)
  86. try:
  87. # 非覆写模式下,判断文件是否存在
  88. if not overwrite and os.path.exists(picPath) and os.path.isfile(picPath):
  89. print('Already Exists <<')
  90. else:
  91. saveFile(getPicUrl(picUrl), picPath)
  92. # except requests.exceptions.ConnectionError:
  93. # print('链接失败')
  94. # print('Failed <<')
  95. # time.sleep(1)
  96. # except requests.exceptions.ConnectTimeout:
  97. # print('链接超时')
  98. # print('Failed <<')
  99. # time.sleep(1)
  100. # except requests.exceptions.ReadTimeout:
  101. # print('返回数据超时')
  102. # print('Failed <<')
  103. # time.sleep(1)
  104. except Exception as e:
  105. print(e)
  106. if(maxretry < 1):
  107. print('Failed <<')
  108. time.sleep(1)
  109. for ri in range(0, maxretry): # 重获链接尝试下载
  110. try:
  111. print('>> Retry times ' + str(ri + 1) + ':')
  112. saveFile(getPicUrl(picUrl), picPath)
  113. except Exception as e2:
  114. print(e2)
  115. if(ri == maxretry - 1):
  116. print('Failed <<')
  117. time.sleep(1)
  118. else: # 下载成功,结束循环
  119. print('Succeed <<')
  120. i = i + 1
  121. break
  122. else:
  123. print('Succeed <<')
  124. i = i + 1
  125. print('||本页共下载 %d 个文件,其中 %d 个成功。' % (imgnum, i))
  126. return [imgnum, i]
  127. def getGallery(url): # 主页,输入url
  128. if (url.find('https://e-hentai.org/g/') != -1):
  129. url = url.partition('?p')[0] # 从参数出现的第一个位置起,将字符串分成包含前中后三个元素的元组
  130. print('== 正在获取内容...==')
  131. try:
  132. site = requests.get(url, headers=headers)
  133. # print(str(site.cookies))
  134. # print(str(site.headers))
  135. content = site.text
  136. # 推荐使用lxml解析器解析而不是默认的html解析器,更快,更强
  137. soup = BeautifulSoup(content, 'lxml')
  138. # 获取分页数,ptds是当前页的class,不是最后一页的;ptt是头部页码table的类,ptd是底部页码table类名
  139. pages = soup.find(class_='ptt').find_all('a')
  140. # for link in pages:
  141. # print(link.get_text())
  142. # 获取列表倒数第二个项,对应页码最大数值
  143. pagecount = int(pages[len(pages) - 2].get_text())
  144. # 获取标题,gn是大标题,gj是日文标题
  145. title = str(soup.h1.get_text())
  146. title2 = str(soup.find(id="gj").get_text())
  147. print('||[漫画名] 《%s》\n||[日文名] 《%s》\n||共 %d 页' %
  148. (title, title2, pagecount))
  149. title = re.sub(r'[\\/:*?"<>|\r\n]', replacechar,
  150. title) # 处理windows不支持的文件名
  151. if not os.path.exists(rootdir + title): # 创建目标文件夹
  152. os.mkdir(rootdir + title)
  153. except Exception as e:
  154. print(e)
  155. print('== 未知错误!已停止解析。==')
  156. else:
  157. totalfile = 0
  158. succeedfile = 0
  159. for pagenum in range(0, pagecount): # range是从参数1到参数2前一个的范围,且参数2须大于参数1
  160. print('||当前第 %d 页' % (pagenum + 1))
  161. targeturl = url
  162. if pagenum != 0: # 不是第一页,需加上页码get参数
  163. targeturl = url + '?p=' + str(pagenum)
  164. returnargs = getPicList(targeturl)
  165. totalfile += returnargs[0]
  166. succeedfile += returnargs[1]
  167. print('== 《%s》下载完成!共 %d 个文件,其中 %d 个成功!==' %
  168. (title, totalfile, succeedfile))
  169. else:
  170. print('<错误:"' + url + '" 不是一个有效的eh漫画目录页面的地址。>\n')
  171. def main():
  172. # init_proxies() # 初始化ip池
  173. # print(str(ip_list))
  174. urls = [] # 允许批量处理,方便睡觉时下载
  175. url = input('<请输入链接(输入空白内容结束):>\n')
  176. while url != "":
  177. urls.append(url)
  178. url = input('== 已输入链接列表 ==\n' + str(urls) + '\n<请输入链接(输入空白内容结束):>\n')
  179. print('== 输入结束 ==')
  180. if(len(urls) > 0):
  181. for item in urls:
  182. getGallery(item)
  183. main()
  184. else:
  185. print('== 结束运行 ==')
  186. main()

四、效果图

五、参考来源

用Python爬E站本的更多相关文章

  1. 萌新学习Python爬取B站弹幕+R语言分词demo说明

    代码地址如下:http://www.demodashi.com/demo/11578.html 一.写在前面 之前在简书首页看到了Python爬虫的介绍,于是就想着爬取B站弹幕并绘制词云,因此有了这样 ...

  2. Python爬虫之爬取站内所有图片

    title date tags layut Python爬虫之爬取站内所有图片 2018-10-07 Python post 目标是 http://www.5442.com/meinv/ 如需在非li ...

  3. 用Python爬取B站、腾讯视频、爱奇艺和芒果TV视频弹幕!

    众所周知,弹幕,即在网络上观看视频时弹出的评论性字幕.不知道大家看视频的时候会不会点开弹幕,于我而言,弹幕是视频内容的良好补充,是一个组织良好的评论序列.通过分析弹幕,我们可以快速洞察广大观众对于视频 ...

  4. 【Python爬虫案例】用Python爬取李子柒B站视频数据

    一.视频数据结果 今天是2021.12.7号,前几天用python爬取了李子柒的油管评论并做了数据分析,可移步至: https://www.cnblogs.com/mashukui/p/1622025 ...

  5. python爬取基础网页图片

    python基础爬虫总结 1.爬取信息原理 与浏览器客户端类似,向网站的服务器发送一个请求,该请求一般是url,也就是网址.之后服务器响应一个html页面给客户端,当然也有其他数据类型的信息,这些就是 ...

  6. 手把手教你使用Python爬取西刺代理数据(下篇)

    /1 前言/ 前几天小编发布了手把手教你使用Python爬取西次代理数据(上篇),木有赶上车的小伙伴,可以戳进去看看.今天小编带大家进行网页结构的分析以及网页数据的提取,具体步骤如下. /2 首页分析 ...

  7. Python 爬取所有51VOA网站的Learn a words文本及mp3音频

    Python 爬取所有51VOA网站的Learn a words文本及mp3音频 #!/usr/bin/env python # -*- coding: utf-8 -*- #Python 爬取所有5 ...

  8. Python快速建站系列-Part.One-组装开发环境

    |版权声明:本文为博主原创文章,未经博主允许不得转载. 源代码都在github上:SmallStudyStation 现在是个demo,但回来会租个服务器,等功能完善了放到服务器上挂着,域名jusot ...

  9. python爬取网站数据

    开学前接了一个任务,内容是从网上爬取特定属性的数据.正好之前学了python,练练手. 编码问题 因为涉及到中文,所以必然地涉及到了编码的问题,这一次借这个机会算是彻底搞清楚了. 问题要从文字的编码讲 ...

随机推荐

  1. Git学习笔记1-Git基础

    1.创建版本库 $ mkdir /d/learngit #创建空目录 $ cd learngit #进入目录 $ git init #将该目录初始化成Git仓库 2.配置信息 1)配置用户信息: $ ...

  2. Rust中的哈希Map

    严谨! fn main() { use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String ...

  3. 初识V4L2(三)-------分析vivi.c 虚拟视频驱动

    1.分配video_device结构体 2.设置 3.注册  video_register_device 分析vivi.c: vivi_init( )//入口函数 vivi_create_instan ...

  4. 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发

    子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ...

  5. Python内容

    1.Python介绍.计算机硬件.网络.变量.数据类型:列表+元组+字典+布尔值+字符串+数字+集合.格式化输出.if判断.for循环.while循环. 2.三元运算.字符编码.文件处理:r/rb(读 ...

  6. Git 克隆远程仓库到本地

    Git 克隆远程仓库到本地 参考 $ git clone --help https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%8E%B7% ...

  7. requests--会话对象,ssl验证

    会话对象 前面我们使用了添加cookie的方式来进行接口的访问,如果有几十个接口都要依赖登录,难道我们都要加上吗? Request的会话对象让你能够跨请求保持某些参数,它也会在同一请求Session实 ...

  8. Xamarin.Forms移动开发系列5 :XAML标记扩展

    摘要 本文主要讲述Xamarin.Forms中XAML的标记扩展. 前言 在Xamarin.Forms移动开发系列4 :XAML基础一文中提到过XAML标记扩展,本文将对标记扩展进行更深入的了解. 大 ...

  9. 洛谷 P3742 umi的函数

    传送门 思路 \(loceaner\)已经蔡虚鲲到连红题都不会做了 因为有\(special\ judge\)所以我们就可以瞎搞了! 由题目可知,只要有一个\(y[i] > x[i]\)则一定没 ...

  10. [LeetCode] 312. Burst Balloons 打气球游戏

    Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by ...