【怒草 https://blog.csdn.net/visionliao/article/details/103935091 未经允许严禁转载,请尊重作者劳动成果。】

快要过年了,大家都在忙些什么呢?一到年底公司各种抢票,备年货,被这过年的气氛一烘,都归心似箭,哪还有心思上班啊。归心似箭=产出低下=一行代码十个错=无聊。于是想起了以前学过一段时间的Python,自己平时也挺爱看电影的,手动点进去看电影详情然后一部一部的去下载太烦了,何不用Python写个自动下载电影的工具呢?诶,这么一想就不无聊了。以前还没那么多XX会员的时候,想看看电影都是去XX天堂去找电影资源,大部分想看的电影还是有的,就它了,爬它!

话说以前玩Python的时候爬过挺多网站的,都是在公司干的(Python不属于公司的业务范围,纯属自己折腾着好玩),我那个负责运维的同事天天跑过来说:你又在爬啥啊,你去看看新闻,某某爬东西又被抓了!出了事你自己负责啊!哎呀我的娘亲,吓的都没继续玩下去了。这个博客是爬取某天堂的资源(具体是哪个天堂下面的代码里会有的),会不会被抓啊?单纯的作为技术讨论,个人练手,不做商业用途应该没事吧?写到这里小手不禁微微颤抖...

得嘞,死就死吧,我不入地狱谁入地狱,先看最终实现效果:

如上,这个下载工具是有界面的(牛皮吧),只要输入一个根地址和电影评分,就可以自动爬电影了,要完成这个工具需要具备以下知识点:

  • PyCharm的安装和使用  这个不多说,猿们都懂,不属于猿类的我也没办法科普了,就是个IDE
  • tkinter  这是个Python GUI开发的库,图中这个简陋的可怜的界面就是基于TK开发的,不想要界面也可以去掉,丝毫不影响爬电影,加上用户界面可以显得屌一点,当然最主要的是我想学习一点新知识
  • 静态网页的分析技巧   相对于动态网站的爬取,静态网站的爬取就显得小菜了,F12会按吧,右键查看网页源代码会吧,通过这些简单的操作就可以查看网页的排版布局规则,然后根据这些规则写爬虫,soeasy
  • 数据持久化  已经下载过的电影,下次再爬电影的时候不希望再下载一次吧,那就把下载过的链接存储起来,下载电影之前去比对是否下载过,以过滤重复下载
  • 迅雷X的下载安装  这个就更不用多说了,作为当代社会主义有为青年,谁没用过迅雷?谁的硬盘里没有几部动作类型的片子?

差不多就这些了,至于实现的技术细节的话,也不多,requests+BeautifulSoup的使用,re正则Python数据类型Python线程dbm、pickle等数据持久化库的使用,等等,这个工具也就这么些知识范畴了。当然,Python是面向对象的,编程思想是所有语言通用的,这个不是一朝一夕的事,也没办法通过语言描述清楚。各位对号入座,以上哪个知识面不足的自己去翻资料学习,我可是直接贴代码的。

说到Python的学习还是多说两句吧,以前学习Python爬虫的时候看的是 @工匠若水 https://blog.csdn.net/yanbober的博客,这哥们的Python文章写的真不错,对于有过编程经验却从没接触过Python的人很有帮助,基本上很快就能上手一个小项目。得嘞,撸代码:

import url_manager
import html_parser
import html_download
import persist_util
from tkinter import *
from threading import Thread
import osclass SpiderMain(object):def __init__(self):self.mUrlManager = url_manager.UrlManager()self.mHtmlParser = html_parser.HtmlParser()self.mHtmlDownload = html_download.HtmlDownload()self.mPersist = persist_util.PersistUtil()# 加载历史下载链接def load_history(self):history_download_links = self.mPersist.load_history_links()if history_download_links is not None and len(history_download_links) > 0:for download_link in history_download_links:self.mUrlManager.add_download_url(download_link)d_log("加载历史下载链接: " + download_link)# 保存历史下载链接def save_history(self):history_download_links = self.mUrlManager.get_download_url()if history_download_links is not None and len(history_download_links) > 0:self.mPersist.save_history_links(history_download_links)def craw_movie_links(self, root_url, score=8):count = 0;self.mUrlManager.add_url(root_url)while self.mUrlManager.has_continue():try:count = count + 1url = self.mUrlManager.get_url()d_log("craw %d : %s" % (count, url))headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36','Referer': url}content = self.mHtmlDownload.down_html(url, retry_count=3, headers=headers)if content is not None:doc = content.decode('gb2312', 'ignore')movie_urls, next_link = self.mHtmlParser.parser_movie_link(doc)if movie_urls is not None and len(movie_urls) > 0:for movie_url in movie_urls:d_log('movie info url: ' + movie_url)content = self.mHtmlDownload.down_html(movie_url, retry_count=3, headers=headers)if content is not None:doc = content.decode('gb2312', 'ignore')movie_name, movie_score, movie_xunlei_links = self.mHtmlParser.parser_movie_info(doc, score=score)if movie_xunlei_links is not None and len(movie_xunlei_links) > 0:for xunlei_link in movie_xunlei_links:# 判断该电影是否已经下载过了is_download = self.mUrlManager.has_download(xunlei_link)if is_download == False:# 没下载过的电影添加到迅雷下载列表d_log('开始下载 ' + movie_name + ', 链接地址: ' + xunlei_link)self.mUrlManager.add_download_url(xunlei_link)os.system(r'"D:\迅雷\Thunder\Program\Thunder.exe" {url}'.format(url=xunlei_link))# 每下载一部电影都实时更新数据库,这样可以保证即使程序异常退出也不会重复下载该电影self.save_history()if next_link is not None:d_log('next link: ' + next_link)self.mUrlManager.add_url(next_link)except Exception as e:d_log('错误信息: ' + str(e))def runner(rootLink=None, scoreLimit=None):if rootLink is None:returnspider = SpiderMain()spider.load_history()if scoreLimit is None:spider.craw_movie_links(rootLink)else:spider.craw_movie_links(rootLink, score=float(scoreLimit))spider.save_history()# rootLink = 'https://www.dytt8.net/html/gndy/dyzz/index.html'
# rootLink = 'https://www.dytt8.net/html/gndy/dyzz/list_23_207.html'
def start(rootLink, scoreLimit):loop_thread = Thread(target=runner, args=(rootLink, scoreLimit,), name='LOOP THREAD')#loop_thread.setDaemon(True)loop_thread.start()#loop_thread.join() # 不能让主线程等待,否则GUI界面将卡死btn_start.configure(state='disable')# 刷新GUI界面,文字滚动效果
def d_log(log):s = log + '\n'txt.insert(END, s)txt.see(END)if __name__ == "__main__":rootGUI = Tk()rootGUI.title('XX电影自动下载工具')# 设置窗体背景颜色black_background = '#000000'rootGUI.configure(background=black_background)# 获取屏幕宽度和高度screen_w, screen_h = rootGUI.maxsize()# 居中显示窗体window_x = (screen_w - 640) / 2window_y = (screen_h - 480) / 2window_xy = '640x480+%d+%d' % (window_x, window_y)rootGUI.geometry(window_xy)lable_link = Label(rootGUI, text='解析根地址: ',\bg='black',\fg='red', \font=('宋体', 12), \relief=FLAT)lable_link.place(x=20, y=20)lable_link_width = lable_link.winfo_reqwidth()lable_link_height = lable_link.winfo_reqheight()input_link = Entry(rootGUI)input_link.place(x=20+lable_link_width, y=20, relwidth=0.5)lable_score = Label(rootGUI, text='电影评分限制: ', \bg='black', \fg='red', \font=('宋体', 12), \relief=FLAT)lable_score.place(x=20, y=20+lable_link_height+10)input_score = Entry(rootGUI)input_score.place(x=20+lable_link_width, y=20+lable_link_height+10, relwidth=0.3)btn_start = Button(rootGUI, text='开始下载', command=lambda: start(input_link.get(), input_score.get()))btn_start.place(relx=0.4, rely=0.2, relwidth=0.1, relheight=0.1)txt = Text(rootGUI)txt.place(rely=0.4, relwidth=1, relheight=0.5)rootGUI.mainloop()

spider_main.py,主代码入口,主要是tkinter 实现的一个简陋的界面,可以输入根地址,电影最低评分。所谓的根地址就是某天堂网站的一类电影的入口,比如进入首页有如下的分类,最新电影、日韩电影、欧美影片、2019精品专区,等等。这里以2019精品专区为例(https://www.dytt8.net/html/gndy/dyzz/index.html),当然,用其它的分类地址入口也是可以的。评分就是个过滤电影的条件,要学会对垃圾电影说不,浪费时间浪费表情,你可以指定大于等于8分的电影才下载,也可以指定大于等于9分等,必须输入数字哈,输入些乱七八糟的东西进去程序会崩溃,这个细节我懒得处理。

'''
URL链接管理类,负责管理爬取下来的电影链接地址,包括新解析出来的链接地址,和已经下载过的链接地址,保证相同的链接地址只会下载一次
'''
class UrlManager(object):def __init__(self):self.urls = set()self.used_urls = set()self.download_urls = set()def add_url(self, url):if url is None:returnif url not in self.urls and url not in self.used_urls:self.urls.add(url)def add_urls(self, urls):if urls is None or len(urls) == 0:returnfor url in urls:self.add_url(url)def has_continue(self):return len(self.urls) > 0def get_url(self):url = self.urls.pop()self.used_urls.add(url)return urldef get_download_url(self):return self.download_urlsdef has_download(self, url):return url in self.download_urlsdef add_download_url(self, url):if url is None:returnif url not in self.download_urls:self.download_urls.add(url)

url_manager.py,注释里写的很清楚了,基本上每个py文件的关键地方我都写了比较详细的注释

import requests
from requests import Timeout'''
HtmlDownload,通过一个链接地址将该html页面整体down下来,然后通过html_parser.py解析其中有价值的信息
'''
class HtmlDownload(object):def __init__(self):self.request_session = requests.session()self.request_session.proxiesdef down_html(self, url, retry_count=3, headers=None, proxies=None, data=None):if headers:self.request_session.headers.update(headers)try:if data:content = self.request_session.post(url, data=data, proxies=proxies)print('result code: ' + str(content.status_code) + ', link: ' + url)if content.status_code == 200:return content.contentelse:content = self.request_session.get(url, proxies=proxies)print('result code: ' + str(content.status_code) + ', link: ' + url)if content.status_code == 200:return content.contentexcept (ConnectionError, Timeout) as e:print('HtmlDownload ConnectionError or Timeout: ' + str(e))if retry_count > 0:self.down_html(url, retry_count-1, headers, proxies, data)return Noneexcept Exception as e:print('HtmlDownload Exception: ' + str(e))

html_download.py,就是用requests将静态网页的内容整体down下来

from bs4 import BeautifulSoup
from urllib.parse import urljoin
import re
import urllib.parse
import base64'''
html页面解析器
'''
class HtmlParser(object):# 解析电影列表页面,获取电影详情页面的链接def parser_movie_link(self, content):try:urls = set()next_link = Nonedoc = BeautifulSoup(content, 'lxml')div_content = doc.find('div', class_='co_content8')if div_content is not None:tables = div_content.find_all('table')if tables is not None and len(tables) > 0:for table in tables:link = table.find('a', class_='ulink')if link is not None:print('movie name: ' + link.text)movie_link = urljoin('https://www.dytt8.net', link.get('href'))print('movie link ' + movie_link)urls.add(movie_link)next = div_content.find('a', text=re.compile(r".*?下一页.*?"))if next is not None:next_link = urljoin('https://www.dytt8.net/html/gndy/dyzz/', next.get('href'))print('movie next link ' + next_link)return urls, next_linkexcept Exception as e:print('解析电影链接地址发生错误: ' + str(e))# 解析电影详情页面,获取电影详细信息def parser_movie_info(self, content, score=8):try:movie_name = None # 电影名称movie_score = 0   # 电影评分movie_xunlei_links = set() # 电影的迅雷下载地址,可能存在多个doc = BeautifulSoup(content, 'lxml')movie_name = doc.find('title').text.replace('迅雷下载_电影天堂', '')#print(movie_name)div_zoom = doc.find('div', id='Zoom')if div_zoom is not None:# 获取电影评分span_txt = div_zoom.texttxt_list = span_txt.split('◎')if txt_list is not None and len(txt_list) > 0:for tl in txt_list:if 'IMDB' in tl or 'IMDb' in tl or 'imdb' in tl or 'IMdb' in tl:txt_score = tl.split('/')[0]print(txt_score)movie_score = re.findall(r"\d+\.?\d*", txt_score)if movie_score is None or len(movie_score) <= 0:movie_score = 1else:movie_score = movie_score[0]print(movie_name + ' IMDB影片分数: ' + str(movie_score))if float(movie_score) < score:print('电影评分低于' + str(score) + ', 忽略')return movie_name, movie_score, movie_xunlei_linkstxt_a = div_zoom.find_all('a', href=re.compile(r".*?ftp:.*?"))if txt_a is not None:# 获取电影迅雷下载地址,base64转成迅雷格式for alink in txt_a:xunlei_link = alink.get('href')'''这里将电影链接转换成迅雷的专用下载链接,后来发现不转换迅雷也能识别xunlei_link = urllib.parse.quote(xunlei_link)xunlei_link = xunlei_link.replace('%3A', ':')xunlei_link = xunlei_link.replace('%40', '@')xunlei_link = xunlei_link.replace('%5B', '[')xunlei_link = xunlei_link.replace('%5D', ']')xunlei_link = 'AA' + xunlei_link + 'ZZ'xunlei_link = base64.b64encode(xunlei_link.encode('gbk'))xunlei_link = 'thunder://' + str(xunlei_link, encoding='gbk')'''print(xunlei_link)movie_xunlei_links.add(xunlei_link)return movie_name, movie_score, movie_xunlei_linksexcept Exception as e:print('解析电影详情页面错误: ' + str(e))

html_parser.py,用bs4解析down下来的html页面内容,根据网页规则过去我们需要的东西,这是爬虫最重要的地方,写爬虫的目的就是想要取出对我们有用的东西。

import dbm
import pickle
import os'''
数据持久化工具类
'''
class PersistUtil(object):def save_data(self, name='No Name', urls=None):if urls is None or len(urls) <= 0:returntry:history_db = dbm.open('downloader_history', 'c')history_db[name] = str(urls)finally:history_db.close()def get_data(self):history_links = set()try:history_db = dbm.open('downloader_history', 'r')for key in history_db.keys():history_links.add(str(history_db[key], 'gbk'))except Exception as e:print('遍历dbm数据失败: ' + str(e))return history_links# 使用pickle保存历史下载记录def save_history_links(self, urls):if urls is None or len(urls) <= 0:returnwith open('DownloaderHistory', 'wb') as pickle_file:pickle.dump(urls, pickle_file)# 获取保存在pickle中的历史下载记录def load_history_links(self):if os.path.exists('DownloaderHistory'):with open('DownloaderHistory', 'rb') as pickle_file:return pickle.load(pickle_file)else:return None

persist_util.py,数据持久化工具类。

这样代码部分就完成了,说下迅雷,我安装的是最新版的迅雷X,一定要如下图一样在迅雷设置打开一键下载功能,否则每次新增一个下载任务都会弹出用户确认框的,还有就是调用迅雷下载资源的代码:os.system(r'"D:\迅雷\Thunder\Program\Thunder.exe" {url}'.format(url=xunlei_link)),一定要去到迅雷安装目录找到Thunder.exe文件,不能用快捷方式的地址(我的电脑->迅雷->右键属性->目标,迅雷X这里显示的路径是快捷方式的路径,不能用这个),否则找不到程序。

到这里你应该就可以电影爬起来了,妥妥的。当然,你想要优化也可以,程序有很多可以优化的地方,比如线程那一块,比如数据持久化那里..... 初学者可以通过这个练手,然后自己去分析分析静态网站的规则,把解析html那一块的代码改改就可以爬其它的网站了,比如那些有着危险动作的电影... 不过这类电影还是少看为妙,要多读书,偶尔看了也要擦擦干净,洗洗干净,要讲卫生。

今天年会,等会儿就可以吃大餐了,哈哈,狗的白~

Python3.x+迅雷x 自动下载高分电影相关推荐

  1. Python3.x+迅雷x 自动下载高分电影,嘿嘿!你懂的

    话说以前玩Python的时候爬过挺多网站的,都是在公司干的(Python不属于公司的业务范围,纯属自己折腾着好玩), 我那个负责运维的同事天天跑过来说:你又在爬啥啊,你去看看新闻,某某爬东西又被抓了! ...

  2. python迅雷自动下载_Python3.x+迅雷x 自动下载高分电影的实现方法

    Python3.x+迅雷x 自动下载高分电影的实现方法 发布时间:2020-09-08 00:08:49

  3. 意外发现迅雷可以自动下载linux对应链接的文件

    下载后用xftp导入更快! 最近在弄centos的java开发环境,就在下mysql,看的韩顺平老师的视频,但是没有他的一些资源包,跟着视频敲的链接,准备直接用 wget http://dev.mys ...

  4. python下载电影速度_我是如何使用python控制迅雷自动下载电影的?

    写了一个脚本爬取了阳光电影的豆瓣高分电影,需要用迅雷帮我一部一部的自动下载好,供我无聊时观看.为什么要一部一部的下? 因为中国移动送了我一张无限流量卡,结果才用了5个G我就被限速到 100kb/s 了 ...

  5. 使用python3爬取网页,利用aria2下载电影,Jellyfin自动更新最新电影

    前言:在我搭建好Jellyfin软件后,因为只能播放本地视频,就想能不能播放网络上的电影,可以每天自动下载并更新,这样就不用我手工下载好,再上传到NAS中播放.或许有更好的方法,那就是直接用电影播放源 ...

  6. BT,eMule,迅雷下载的电影没有字幕的解决方法

    BT,eMule,迅雷下载的电影没有字幕的解决方法 大有经常用BT,eMule,迅雷下载的电影没有字幕,这些电影还大部分都是英文的,对于国人来说,是件很头痛的事. 现在教大家在BT,eMule,迅雷下 ...

  7. python下载电影_打造一款Python实现自动下载电影的“脚本”!那种电影也可以哦!...

    原标题:打造一款Python实现自动下载电影的"脚本"!那种电影也可以哦! 都很有规律不是吗?而在Scrapy里面,就可以设定我们想要的规律,Scrapy就可以对这些符合规律的网址 ...

  8. Python3从零开始爬取今日头条的新闻【五、解析头条视频真实播放地址并自动下载】

    Python3从零开始爬取今日头条的新闻[一.开发环境搭建] Python3从零开始爬取今日头条的新闻[二.首页热点新闻抓取] Python3从零开始爬取今日头条的新闻[三.滚动到底自动加载] Pyt ...

  9. 用Java写一个电影自动下载器

    你好! 下面是一些步骤来帮助你写一个电影自动下载器: 建立一个新的Java项目 选择一个电影下载网站作为数据源, 并使用网络爬虫或API来获取电影的信息(如标题, 时长, 格式, 大小等) 使用Jav ...

  10. 迅雷 API 接口说明文档 -调用迅雷自动下载

    我们可以利用迅雷提供的开放API接口来自动下载文件.详细的接口说明大家可以看下面的. 先要说明一下的就是 迅雷的API接口是用 .com 来调用的 首先就是脚本了,各种语言写法不同,我这里提供用vbs ...

最新文章

  1. 思维 ---- 两两匹配问题 2021杭电多校第6场 E - Median
  2. python中set和frozenset方法和区别
  3. 我的 Serverless 实战 — Serverless 架构理念 ( 后端服务器发展 | Serverless 与 ServerFul | Serverless 定义 | 架构优缺点 )
  4. 实模式与保护模式详解二:地址映射
  5. 用XGBoost调XGBoost?我调我自己?
  6. 每周论文清单:知识图谱,文本匹配,图像翻译,视频对象分割
  7. 进程间的通信----管道
  8. linux加密框架 crypto 算法管理 - 算法查找接口
  9. PostgreSQL 优化器代码概览 1
  10. 相机下载_索尼黑卡相机与手机互联APP相关
  11. Tomcat配置多个Service,多个同名的应用运行在一个tomcat下
  12. php加密 java rsa_PHP的DES加密和RSA签名(兼容java)
  13. 第1章 操作系统引论课后答案
  14. GAEA Winsieve v1.2 1CD(快速输入和打印结晶粒度分析曲线)
  15. git 下载指定历史版本
  16. 飞信2008协议抓包(1)
  17. 怎样查看PPT中的字数
  18. 美团java后端_美团笔试题(Java后端5题2小时)(示例代码)
  19. Pytorch—模型微调(fine-tune)
  20. 天天学算法——搜索热词关联(TopK)

热门文章

  1. linux0.11 阅读笔记
  2. 记在创口贴上的超实用IDEA Eclipse快捷方式
  3. 安装易飞ERP打开出错的两例
  4. java蓝桥杯合根植物_Java实现蓝桥杯 历届试题 合根植物
  5. 安卓手机虚拟键盘定位position:fixed问题
  6. 用十条命令在一分钟内检查Linux服务器性能[转]
  7. 麻省理工大学公开课笔记:算法导论(二)——课程简介及算法分析
  8. 快速入门——深度学习理论解析与实战应用
  9. 【JZOJ3339】wyl8899和法法塔的游戏【暴力】
  10. 交换机端口mtu值最大_H3CCAS接口MTU值方法