Python3.x+迅雷x 自动下载高分电影的实现方法
快要过年了,大家都在忙些什么呢?一到年底公司各种抢票,备年货,被这过年的气氛一烘,都归心似箭,哪还有心思上班啊。归心似箭=产出低下=一行代码十个错=无聊。于是想起了以前学过一段时间的Python,自己平时也挺爱看电影的,手动点进去看电影详情然后一部一部的去下载太烦了,何不用Python写个自动下载电影的工具呢?诶,这么一想就不无聊了。以前还没那么多XX会员的时候,想看看电影都是去XX天堂去找电影资源,大部分想看的电影还是有的,就它了,爬它!
话说以前玩Python的时候爬过挺多网站的,都是在公司干的(Python不属于公司的业务范围,纯属自己折腾着好玩),我那个负责运维的同事天天跑过来说:你又在爬啥啊,你去看看新闻,某某爬东西又被抓了!出了事你自己负责啊!哎呀我的娘亲,吓的都没继续玩下去了。这个博客是爬取某天堂的资源(具体是哪个天堂下面的代码里会有的),会不会被抓啊?单纯的作为技术讨论,个人练手,不做商业用途应该没事吧?写到这里小手不禁微微颤抖...
得嘞,死就死吧,我不入地狱谁入地狱,先看最终实现效果:
如上,这个下载工具是有界面的(牛皮吧),只要输入一个根地址和电影评分,就可以自动爬电影了,要完成这个工具需要具备以下知识点:
- PyCharm的安装和使用这个不多说,猿们都懂,不属于猿类的我也没办法科普了,就是个IDE
- tkinter这是个PythonGUI开发的库,图中这个简陋的可怜的界面就是基于TK开发的,不想要界面也可以去掉,丝毫不影响爬电影,加上用户界面可以显得屌一点,当然最主要的是我想学习一点新知识静态网页的分析技巧相对于动态网站的爬取,静态网站的爬取就显得小菜了,F12会按吧,右键查看网页源代码会吧,通过这些简单的操作就可以查看网页的排版布局规则,然后根据这些规则写爬虫,soeasy
- 数据持久化已经下载过的电影,下次再爬电影的时候不希望再下载一次吧,那就把下载过的链接存储起来,下载电影之前去比对是否下载过,以过滤重复下载
- 迅雷X的下载安装这个就更不用多说了,作为当代社会主义有为青年,谁没用过迅雷?谁的硬盘里没有几部动作类型的片子?
差不多就这些了,至于实现的技术细节的话,也不多,requests+BeautifulSoup的使用,re正则,Python数据类型,Python线程,dbm、pickle等数据持久化库的使用,等等,这个工具也就这么些知识范畴了。当然,Python是面向对象的,编程思想是所有语言通用的,这个不是一朝一夕的事,也没办法通过语言描述清楚。各位对号入座,以上哪个知识面不足的自己去翻资料学习,我可是直接贴代码的。
说到Python的学习还是多说两句吧,以前学习Python爬虫的时候看的是@工匠若水https://blog.csdn.net/yanbober的博客,这哥们的Python文章写的真不错,对于有过编程经验却从没接触过Python的人很有帮助,基本上很快就能上手一个小项目。得嘞,撸代码:
importurl_manager
importhtml_parser
importhtml_download
importpersist_util
fromtkinterimport*
fromthreadingimportThread
importos
classSpiderMain(object):
def__init__(self):
self.mUrlManager=url_manager.UrlManager()
self.mHtmlParser=html_parser.HtmlParser()
self.mHtmlDownload=html_download.HtmlDownload()
self.mPersist=persist_util.PersistUtil()
#加载历史下载链接
defload_history(self):
history_download_links=self.mPersist.load_history_links()
ifhistory_download_linksisnotNoneandlen(history_download_links)>0:
fordownload_linkinhistory_download_links:
self.mUrlManager.add_download_url(download_link)
d_log("加载历史下载链接:"+download_link)
#保存历史下载链接
defsave_history(self):
history_download_links=self.mUrlManager.get_download_url()
ifhistory_download_linksisnotNoneandlen(history_download_links)>0:
self.mPersist.save_history_links(history_download_links)
defcraw_movie_links(self,root_url,score=8):
count=0;
self.mUrlManager.add_url(root_url)
whileself.mUrlManager.has_continue():
try:
count=count+1
url=self.mUrlManager.get_url()
d_log("craw%d:%s"%(count,url))
headers={
'User-Agent':'Mozilla/5.0(WindowsNT6.1;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/62.0.3202.62Safari/537.36',
'Referer':url
}
content=self.mHtmlDownload.down_html(url,retry_count=3,headers=headers)
ifcontentisnotNone:
doc=content.decode('gb2312','ignore')
movie_urls,next_link=self.mHtmlParser.parser_movie_link(doc)
ifmovie_urlsisnotNoneandlen(movie_urls)>0:
formovie_urlinmovie_urls:
d_log('movieinfourl:'+movie_url)
content=self.mHtmlDownload.down_html(movie_url,retry_count=3,headers=headers)
ifcontentisnotNone:
doc=content.decode('gb2312','ignore')
movie_name,movie_score,movie_xunlei_links=self.mHtmlParser.parser_movie_info(doc,score=score)
ifmovie_xunlei_linksisnotNoneandlen(movie_xunlei_links)>0:
forxunlei_linkinmovie_xunlei_links:
#判断该电影是否已经下载过了
is_download=self.mUrlManager.has_download(xunlei_link)
ifis_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()
ifnext_linkisnotNone:
d_log('nextlink:'+next_link)
self.mUrlManager.add_url(next_link)
exceptExceptionase:
d_log('错误信息:'+str(e))
defrunner(rootLink=None,scoreLimit=None):
ifrootLinkisNone:
return
spider=SpiderMain()
spider.load_history()
ifscoreLimitisNone:
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'
defstart(rootLink,scoreLimit):
loop_thread=Thread(target=runner,args=(rootLink,scoreLimit,),name='LOOPTHREAD')
#loop_thread.setDaemon(True)
loop_thread.start()
#loop_thread.join()#不能让主线程等待,否则GUI界面将卡死
btn_start.configure(state='disable')
#刷新GUI界面,文字滚动效果
defd_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)/2
window_y=(screen_h-480)/2
window_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链接管理类,负责管理爬取下来的电影链接地址,包括新解析出来的链接地址,和已经下载过的链接地址,保证相同的链接地址只会下载一次 ''' classUrlManager(object): def__init__(self): self.urls=set() self.used_urls=set() self.download_urls=set() defadd_url(self,url): ifurlisNone: return ifurlnotinself.urlsandurlnotinself.used_urls: self.urls.add(url) defadd_urls(self,urls): ifurlsisNoneorlen(urls)==0: return forurlinurls: self.add_url(url) defhas_continue(self): returnlen(self.urls)>0 defget_url(self): url=self.urls.pop() self.used_urls.add(url) returnurl defget_download_url(self): returnself.download_urls defhas_download(self,url): returnurlinself.download_urls defadd_download_url(self,url): ifurlisNone: return ifurlnotinself.download_urls: self.download_urls.add(url)
url_manager.py,注释里写的很清楚了,基本上每个py文件的关键地方我都写了比较详细的注释
importrequests
fromrequestsimportTimeout
'''
HtmlDownload,通过一个链接地址将该html页面整体down下来,然后通过html_parser.py解析其中有价值的信息
'''
classHtmlDownload(object):
def__init__(self):
self.request_session=requests.session()
self.request_session.proxies
defdown_html(self,url,retry_count=3,headers=None,proxies=None,data=None):
ifheaders:
self.request_session.headers.update(headers)
try:
ifdata:
content=self.request_session.post(url,data=data,proxies=proxies)
print('resultcode:'+str(content.status_code)+',link:'+url)
ifcontent.status_code==200:
returncontent.content
else:
content=self.request_session.get(url,proxies=proxies)
print('resultcode:'+str(content.status_code)+',link:'+url)
ifcontent.status_code==200:
returncontent.content
except(ConnectionError,Timeout)ase:
print('HtmlDownloadConnectionErrororTimeout:'+str(e))
ifretry_count>0:
self.down_html(url,retry_count-1,headers,proxies,data)
returnNone
exceptExceptionase:
print('HtmlDownloadException:'+str(e))
html_download.py,就是用requests将静态网页的内容整体down下来
frombs4importBeautifulSoup
fromurllib.parseimporturljoin
importre
importurllib.parse
importbase64
'''
html页面解析器
'''
classHtmlParser(object):
#解析电影列表页面,获取电影详情页面的链接
defparser_movie_link(self,content):
try:
urls=set()
next_link=None
doc=BeautifulSoup(content,'lxml')
div_content=doc.find('div',class_='co_content8')
ifdiv_contentisnotNone:
tables=div_content.find_all('table')
iftablesisnotNoneandlen(tables)>0:
fortableintables:
link=table.find('a',class_='ulink')
iflinkisnotNone:
print('moviename:'+link.text)
movie_link=urljoin('https://www.dytt8.net',link.get('href'))
print('movielink'+movie_link)
urls.add(movie_link)
next=div_content.find('a',text=re.compile(r".*?下一页.*?"))
ifnextisnotNone:
next_link=urljoin('https://www.dytt8.net/html/gndy/dyzz/',next.get('href'))
print('movienextlink'+next_link)
returnurls,next_link
exceptExceptionase:
print('解析电影链接地址发生错误:'+str(e))
#解析电影详情页面,获取电影详细信息
defparser_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')
ifdiv_zoomisnotNone:
#获取电影评分
span_txt=div_zoom.text
txt_list=span_txt.split('◎')
iftxt_listisnotNoneandlen(txt_list)>0:
fortlintxt_list:
if'IMDB'intlor'IMDb'intlor'imdb'intlor'IMdb'intl:
txt_score=tl.split('/')[0]
print(txt_score)
movie_score=re.findall(r"\d+\.?\d*",txt_score)
ifmovie_scoreisNoneorlen(movie_score)<=0:
movie_score=1
else:
movie_score=movie_score[0]
print(movie_name+'IMDB影片分数:'+str(movie_score))
iffloat(movie_score)
html_parser.py,用bs4解析down下来的html页面内容,根据网页规则过去我们需要的东西,这是爬虫最重要的地方,写爬虫的目的就是想要取出对我们有用的东西。
importdbm
importpickle
importos
'''
数据持久化工具类
'''
classPersistUtil(object):
defsave_data(self,name='NoName',urls=None):
ifurlsisNoneorlen(urls)<=0:
return
try:
history_db=dbm.open('downloader_history','c')
history_db[name]=str(urls)
finally:
history_db.close()
defget_data(self):
history_links=set()
try:
history_db=dbm.open('downloader_history','r')
forkeyinhistory_db.keys():
history_links.add(str(history_db[key],'gbk'))
exceptExceptionase:
print('遍历dbm数据失败:'+str(e))
returnhistory_links
#使用pickle保存历史下载记录
defsave_history_links(self,urls):
ifurlsisNoneorlen(urls)<=0:
return
withopen('DownloaderHistory','wb')aspickle_file:
pickle.dump(urls,pickle_file)
#获取保存在pickle中的历史下载记录
defload_history_links(self):
ifos.path.exists('DownloaderHistory'):
withopen('DownloaderHistory','rb')aspickle_file:
returnpickle.load(pickle_file)
else:
returnNone
persist_util.py,数据持久化工具类。
这样代码部分就完成了,说下迅雷,我安装的是最新版的迅雷X,一定要如下图一样在迅雷设置打开一键下载功能,否则每次新增一个下载任务都会弹出用户确认框的,还有就是调用迅雷下载资源的代码:os.system(r'"D:\迅雷\Thunder\Program\Thunder.exe"{url}'.format(url=xunlei_link)),一定要去到迅雷安装目录找到Thunder.exe文件,不能用快捷方式的地址(我的电脑->迅雷->右键属性->目标,迅雷X这里显示的路径是快捷方式的路径,不能用这个),否则找不到程序。
到这里你应该就可以电影爬起来了,妥妥的。当然,你想要优化也可以,程序有很多可以优化的地方,比如线程那一块,比如数据持久化那里.....初学者可以通过这个练手,然后自己去分析分析静态网站的规则,把解析html那一块的代码改改就可以爬其它的网站了,比如那些有着危险动作的电影...不过这类电影还是少看为妙,要多读书,偶尔看了也要擦擦干净,洗洗干净,要讲卫生。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。