首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python脚本从8 8muses下载成人漫画

Python脚本从8 8muses下载成人漫画
EN

Code Review用户
提问于 2019-04-27 06:03:55
回答 1查看 2.4K关注 0票数 3

我使用BeautifulSoup和Selenium制作了一个简单的python脚本,可以自动从8个缪斯下载成人漫画。我之所以使用selenium,是因为该网站使用javascript加载图像。

输入图库url并下载位置开始下载。样本库urls:

https://www.8muses.com/comics/album/MilfToon-Comics/Milfage/Issue-1 https://www.8muses.com/comics/album/MilfToon-Comics/Lemonade/Lemonade-1

我想知道对代码或替代方法的改进,以使其工作得更快。谢谢!

代码: app.py

代码语言:javascript
复制
import os
from multiprocessing.dummy import Pool
from queue import Queue
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
from threading import Thread
import urllib.request
import requests 
import shutil

options = Options()
options.headless = True
chrome_driver_path = r"C:\Users\NH\PycharmProjects\SeleniumTest\drivers\chromedriver.exe"
base_url = "https://www.8muses.com"

def fetch_image_url(url,filename,download_location):
    driver = webdriver.Chrome(chrome_driver_path, chrome_options=options)
    driver.get(url)
    page = driver.page_source
    soup = BeautifulSoup(page,"lxml")
    image_url = "http:"+soup.find("img",{"class":"image"})['src']
    download_image(image_url,filename,download_location)

def download_image(image_url,filename,download_location):
    r = requests.get(image_url,stream=True, headers={'User-agent': 'Mozilla/5.0'})
    if r.status_code == 200:
        with open(os.path.join(download_location,str(filename)+".png"), 'wb') as f:
            r.raw.decode_content = True
            shutil.copyfileobj(r.raw, f)
    print("Downloaded page {pagenumber}".format(pagenumber=filename))


if __name__=="__main__":
    print("Album Url : ")
    album_url = input()
    print("Download Location : ")
    download_location = input()
    driver = webdriver.Chrome(chrome_driver_path, chrome_options=options)
    print("Loading Comic...")
    driver.get(album_url)
    album_html = driver.page_source
    print("Comic successfully loaded")
    soup = BeautifulSoup(album_html,"lxml")
    comic_name = soup.find("title").text.split("|")[0].strip()
    download_location = os.path.join(download_location,comic_name)
    os.mkdir(download_location)
    print("Finding comic's pages")
    images = soup.find_all("a",{"class":"c-tile t-hover"})
    page_urls = []
    pages = []
    threads = []
    for image in images:
        page_urls.append(base_url + image['href'])
    print("Found {} pages".format(len(page_urls)))
    for i in  range(len(page_urls)):
            pages.append((page_urls[i],i,download_location))
    p = Pool(3)  # 3 threads in the pool
    p.starmap(fetch_image_url,pages)
    p.close()
    p.join()
    driver.quit()
    print ("DONE ! Happy Reading ")

项目Github:https://github.com/ggrievous/8muser

EN

回答 1

Code Review用户

回答已采纳

发布于 2019-04-29 04:01:22

没有理由在这里使用selenium。与其接触selenium,不如先尝试更简单的路径。在没有javascript的情况下加载页面,看看是否可以找到任何有用的信息,说明图像是如何到达那里的。一定有什么东西(也许是AJAX)可以为它们获取URL。他们不只是魔术般地出现!

事实证明,如果你这样做,你会发现没有任何花哨的JS东西。照片就在那里,就像这样:

代码语言:javascript
复制
<div class="image">
  <img class="lazyload" data-src="/image/th/QD-H-4F3JpxykaxnIIFbrixlkt4rwBphjoSmX2E8fvoJ8JanT-+S2MdyjKTADNm+SJdCVhXQwkdIZ0tQel-n8-y70M9EOTmeW06uA5ubLwnl2gi5X14+yw6GKhNbhj7S.jpg">
</div>

这意味着,您可以使用一行BeautifulSoup提取所有这些URL:

代码语言:javascript
复制
urls = [img['data-src'] for img in doc.find_all('img', class_='lazyload')]

现在,关于您的代码的一些评论:

  • PEP8!你的间隔不一致。充分利用垂直空格。用你喜欢的段落来表达。这让事情更容易读懂。
  • 您不需要selenium,但是您绝对不应该在开源项目中硬编码驱动程序路径。有多少人在电脑上的C:\Users\NH\PycharmProjects\SeleniumTest\drivers\chromedriver.exe上有一个硒驱动器?
  • 很好地使用函数来分离关注点
  • 您可能应该使用BeautifulSoup(page, 'html5lib')而不是lxml。
  • 您的image_url结构有点草率。通常,我们使用urllib.path来构建路径,而不是仅仅进行字符串连接。
  • 使用pathlib而不是os.path
  • 'Mozilla/5.0'不是一个会欺骗任何人的用户代理。如果你真的想躲在雷达下,就用一个真正的UA
  • 但是这些都不重要,因为你似乎尽可能快地请求页面。在下载之间添加sleep()s。切断你的刮刀。
  • threading在Python中有点没用。这在某种程度上是一个I/O绑定任务(线程非常适合这个任务),但是HTML解析和提取肯定可以与web请求同时进行(但是线程不允许这样做)。你几乎总是想要找到multiprocessing
  • 使用池的上下文管理器而不是手动调用close()join()
代码语言:javascript
复制
with Pool() as pool:
    pool.imap_unorderd(fetch_image_url, pages)
  • 另外,不要向Pool传递参数。它默认为CPU核心的数量,这几乎总是您想要的。
  • starmap被命令并阻塞。它只能按部就班地处理。在本例中,这是可以的,因为您实际上没有返回任何内容,但是如果您说在做数学时,您可能需要imap_unordered,它会在结果到达时产生结果(很可能是无序的)。
  • 不要从单独的进程中提取print。您希望有一个进程写入stdout,否则您就可以编写争用(您可能不会遇到这种争用,因为您的字符串可能适合stdout缓冲区,但在某些情况下它们可能不适合)。

但是,这一切最终导致了以下建议:不要使用Python下载东西!

特别是因为这种抓取看起来并不像库一样有用(相反,您似乎只是提供了一个CLI实用程序供人类下载这些东西)。考虑到这一点,不重新发明方向盘是更明智和安全的。有些工具已经很好地完成了这样的工作:即wget (看起来您在windows上,您可以而且应该使用Ubuntu子系统,其中包含wget)。wget特别适合这项工作,并具有大量的内置功能,这将对您非常有用。这包括:

  • 不是重新下载东西
  • 节流(包括随机延迟)
  • 在灾难性(程序崩溃)失败后重新启动
  • 根据HTTP规范重试请求

所有这些都是您的脚本目前无法完成的事情。特别是,在python中这样做非常容易:

代码语言:javascript
复制
pages = download_hundreds_of_pages()  # takes hours...
for page in paages:  # oops, this NameErrors and you lose everything you've downloaded
  pass

这样的错误太容易犯了。您可以使用以下工作流完全避免它们:

  1. 建立一个您想要下载的urls列表(可能是用python)
  2. 使用wget -nc -i urls.txt下载
  3. 必要时重复

对于您来说,这将涉及到一个包含图像的urls列表。那就做wget -nc -i pages.txt。它将将所有页面下载到当前目录。然后,您可以制作一个Python脚本,它使用漂亮的汤(和我前面提到的行)来提取图像urls:python3 extract_image_urls.py > image_urls.txt。然后下载它们做wget -nc -i image_urls.txt。如果您的python脚本在任何时候都失败了,那么您不会丢失已经完成的所有下载。您可以在一个方便的bash脚本中包装所有这些。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/219237

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档