详解Python爬取并下载《电影天堂》3千多部电影


Posted in Python onApril 26, 2019

不知不觉,玩爬虫玩了一个多月了。

我愈发觉得,爬虫其实并不是什么特别高深的技术,它的价值不在于你使用了什么特别牛的框架,用了多么了不起的技术,它不需要。它只是以一种自动化搜集数据的小工具,能够获取到想要的数据,就是它最大的价值。

我的爬虫课老师也常跟我们强调,学习爬虫最重要的,不是学习里面的技术,因为前端技术在不断的发展,爬虫的技术便会随着改变。学习爬虫最重要的是,学习它的原理,万变不离其宗。

爬虫说白了是为了解决需要,方便生活的。如果能够在日常生活中,想到并应用爬虫去解决实际的问题,那么爬虫的真正意义也久发挥出来了。

这是些闲话啦,有感而发而已。

最近有点片荒,不知道该看什么电影,而且有些电影在网上找好久也找不到资源。后来我了解到这个网站,发现最近好多不错的电影上面都有资源(这里我就先不管它的来源正不正规啦,#掩面)。

所以这次我们要爬取的网站是:《电影天堂》,屯一些电影,等无聊的时候拿出来看看,消遣消遣也是不错。

详解Python爬取并下载《电影天堂》3千多部电影

这次的网站,从爬虫的技术角度上来讲,难度不大,而且可以说是非常简单了。但是,它实用啊!你想嘛,早上上班前跑一下爬虫,晚上回家以后已经有几十部最新大片在你硬盘里等着你啦,累了一天躺床上看看电影,这种感觉是不是很爽啊。

而且正因为这个爬虫比较简单,所以我会写的稍微细一点,争取让 python 小白们也能尽可能看懂,并且能够在这个爬虫的基础上修改,得到爬取这个网站其他板块或者其他电影网站的爬虫。

写在前面的话

在编写爬虫程序之前,我先捋一捋我们的思路。

  1. 爬虫的原理,是通过给定的一个 URL(就是类似于 http://www.baidu.com 这样的,俗称网址的东东) 请求,去访问一个网页,获取那个网页上的源代码(不知道源代码的,随便打开一个网页,右键,查看网页源代码,出来的一大堆像乱码一样的东西就是网页源代码,我们需要的数据就藏在这些源代码里面)并返回来。
  2. 然后,通过一些手段(比如说json库,BeautifulSoup库,正则表达式等)从网页源代码中筛选出我们想要的数据(当然,前提是我们需要分析网页结构,知道自己想要什么数据,以及这些数据存放在网页的哪儿,存放的位置有什么特征等)。
  3. 最后,将我们获取到的数据按照一定的格式,存储到本地或者数据库中,这样就完成了爬虫的全部工作。

当然,也有一些 「骚操作」,如果你嫌爬虫效率低,可以开多线程(就是相当于几十只爬虫同时给你爬,效率直接翻了几十倍);如果担心爬取频率过高被网站封 IP,可以挂 IP 代理(相当于打几枪换个地方,对方网站就不知道你究竟是爬虫还是正常访问的用户了);如果对方网站有反爬机制,那么也有一些骚操作可以绕过反爬机制(有点黑客攻防的感觉,有木有!)。这些都是后话了。

爬虫部分

一、分析网站结构(以动作片电影为例)

1. 分析网页的 URL 的组成结构

首先,我们需要分析网页的 URL 的组成结构,主要关注两方面,一是如何切换选择的电影类型,二是网页如何翻页的。

点击网页上的电影类型的按钮,观察地址栏中的 URL ,发现网址和电影类型的关系如下:

电影类型 网址
剧情片 https://www.dy2018.com/0/
喜剧片 https://www.dy2018.com/1/
动作片 https://www.dy2018.com/2/
爱情片 https://www.dy2018.com/3/
科幻片 https://www.dy2018.com/4/
动画片 https://www.dy2018.com/5/
悬疑片 https://www.dy2018.com/6/
惊悚片 https://www.dy2018.com/7/
恐怖片 https://www.dy2018.com/8/
记录片 https://www.dy2018.com/9/
...... ......
灾难片 https://www.dy2018.com/18/
武侠片 https://www.dy2018.com/19/
古装片 https://www.dy2018.com/20/

发现规律了吧,以后如果想爬其他类型的电影,只要改变 url 中的数字即可,甚至你可以写一个循环,把所有板块中的电影全部爬取下来。

随便打开一个分类,我们滚动到页面的最下面,发现这里有翻页的按钮,点击按钮翻页的同时,观察 url 的变化。

页码 URL
第一页 https://www.dy2018.com/2/index.html
第二页 https://www.dy2018.com/2/index_2.html
第三页 https://www.dy2018.com/2/index_3.html
第四页 https://www.dy2018.com/2/index_4.html

除了第一页是 「index」外,其余页码均是 「index_页码」的形式。

所以我们基本掌握了网站的 url 的构成形式,这样我们就可以通过自己构造 url 来访问任意类型电影的任意一页了,是不是很酷。

2. 分析网站的页面结构

其次,我们分析一下网站的页面结构,看一看我们需要的信息都藏在网页的什么地方(在这之前我们先要明确一下我们需要哪些数据),由于我们这个目的是下载电影,所以对我有用的数据只有两个,电影名称和下载电影的磁力链接。

按 F12 召唤出开发者工具(这个工具可以帮助你快速定位网页中的元素在 html 源代码中位置)。

详解Python爬取并下载《电影天堂》3千多部电影

然后,我们可以发现,电影列表中,每一部电影的信息存放在一个 <table> 标签里,而电影的名字,就藏在里面的一个 <a> 标签中。电影下载的磁力链接在电影的详情页面,而电影详情页面的网址也在这个 <a> 标签中( href 属性的值)。

详解Python爬取并下载《电影天堂》3千多部电影

 而下载的磁力链接,存放在 <tbody> 标签下的 <a> 标签中,是不是很好找啊!

最后我们来缕一缕思路,一会儿我们准备这样操作:通过前面的网址的构造规则,访问到网站的某一页,然后获取到这个页面里的所有 table 标签(这里存放着电影的数据),然后从每一个 table 标签中找到存有电影名称的 a 标签(这里可以拿到电影名称以及详情页面的网址),然后通过这里获取的网址访问电影的详情页面,在详情页面挑选出 <tbody> 标签下的 <a> 标签(这里存放着电影的下载链接),这样我们就找到了我们所需要的全部数据了,是不是很简单啊。

二、爬虫编码阶段 

爬虫的程序,我一般习惯把它分成五个部分, 一是主函数,作为程序的入口,二是爬虫调度器,三是网络请求函数,四是网页解析函数,五是数据存储函数。

  1. get_data :其参数是目标网页 url,这个函数可以模拟浏览器访问 url,获取并将网页的内容返回。
  2. parse_data :其参数是网页的内容,这个函数主要是用来解析网页内容,筛选提取出关键的信息,并打包成列表返回。
  3. save_data :其参数是数据的列表,这个函数用来将列表中的数据写入本地的文件中。
  4. main :这个函数是爬虫程序的调度器,可以根据事先分析好的 url 的规则,不断的构造新的请求 url,并调用其他三个函数,获取数据并保存到本地,直到结束。
  5. if __name__ == '__main__' :这是主程序的入口,在这里调用 main 函数,启动爬虫调度器即可。
# 我们用到的库
import requests
import bs4
import re
import pandas as pd

1. 网络请求函数 :get_data (url)

负责访问指定的 url 网页,并将网页的内容返回,此部分功能比较简单固定,一般不需要做修改(除非你要挂代理,或者自定义请求头等,可以做一些相应的调整)。

def get_data(url):
  '''
  功能:访问 url 的网页,获取网页内容并返回
  参数:
    url :目标网页的 url
  返回:目标网页的 html 内容
  '''
  headers = {
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
  }
 
  try:
    r = requests.get(url, headers=headers)
    r.raise_for_status()
    return r.text
  
  except requests.HTTPError as e:
    print(e)
    print("HTTPError")
  except requests.RequestException as e:
    print(e)
  except:
    print("Unknown Error !")

2. 网页解析函数:parse_data(html)

 这个函数是整个爬虫程序的核心所在,整体思路在上一部分已经讲过了。我这里使用的库是 BeautifulSoup。

这部分的写法多种多样,有很多发挥的空间,也没有什么太多固定的模式,因为这部分的写法是要随着不同网站的页面结构来做调整的,比如说有的网站提供了数据的 api 接口,那么返回的数据就是 json 格式,我们只需要调用 json 库就可以完成数据解析,而大部分的网站只能通过从网页源代码中一层层筛选(筛选手段也多种多样,什么正则表达式,beautifulsoup等等)。

这里需要根据数据的形式来选择不同的筛选策略,所以,知道原理就可以了,习惯什么方法就用什么方法,反正最后能拿到数据就好了。

def parse_data(html):
  '''
  功能:提取 html 页面信息中的关键信息,并整合一个数组并返回
  参数:html 根据 url 获取到的网页内容
  返回:存储有 html 中提取出的关键信息的数组
  '''
  bsobj = bs4.BeautifulSoup(html,'html.parser')
  info = []
  
  # 获取电影列表
  tbList = bsobj.find_all('table', attrs = {'class': 'tbspan'})
  
  # 对电影列表中的每一部电影单独处理
  for item in tbList:
 
    movie = []
    link = item.b.find_all('a')[1]
 
    # 获取电影的名称
    name = link["title"]
 
    # 获取详情页面的 url
    url = 'https://www.dy2018.com' + link["href"]
 
    # 将数据存放到电影信息列表里
    movie.append(name)
    movie.append(url)
    
    try:
      # 访问电影的详情页面,查找电影下载的磁力链接
      temp = bs4.BeautifulSoup(get_data(url),'html.parser')
      tbody = temp.find_all('tbody')
      
      # 下载链接有多个(也可能没有),这里将所有链接都放进来
      for i in tbody:
        download = i.a.text
        movie.append(download)
        
      #print(movie)
 
      # 将此电影的信息加入到电影列表中
      info.append(movie)
      
    except Exception as e:
      print(e)
  
  return info

3. 数据存储函数:save_data(data)

 这个函数目的是将数据存储到本地文件或数据库中,具体的写法要根据实际需要的存储形式来定,我这里是将数据存放在本地的 csv 文件中。

当然这个函数也并不只能做这些事儿,比如你可以在这里写一些简单的数据处理的操作,比如说:数据清洗,数据去重等操作。

def save_data(data):
  '''
  功能:将 data 中的信息输出到文件中/或数据库中。
  参数:data 将要保存的数据 
  '''
  filename = 'Data/电影天堂/动作片.csv'
  
  dataframe = pd.DataFrame(data)
  dataframe.to_csv(filename, mode='a', index=False, sep=',', header=False)

4. 爬虫调度器:main()

这个函数负责根据 url 生成规则,构造新的 url 请求,然后依次调用网络请求函数,网页解析函数,数据存储函数,爬取并保存该页数据。

所谓爬虫调度器,就是控制爬虫什么时候开始爬,多少只爬虫一起爬,爬哪个网页,爬多久休息一次,等等这些事儿。

def main():
  # 循环爬取多页数据
  for page in range(1, 114):
    print('正在爬取:第' + str(page) + '页......')    
    # 根据之前分析的 URL 的组成结构,构造新的 url
    if page == 1:
      index = 'index'
    else:
      index = 'index_' + str(page)      
    url = 'https://www.dy2018.com/2/'+ index +'.html'
    # 依次调用网络请求函数,网页解析函数,数据存储函数,爬取并保存该页数据
    html = get_data(url)
    movies = parse_data(html)
    save_data(movies)
    
    print('第' + str(page) + '页完成!')

5. 主函数:程序入口

主函数作为程序的入口,只负责启动爬虫调度器。

这里我一般习惯在 main() 函数前后输出一条语句,以此判断爬虫程序是否正常启动和结束。

if __name__ == '__main__':
  print('爬虫启动成功!')
  main()
  print('爬虫执行完毕!')

三、程序运行结果

 运行了两个小时左右吧,终于爬完了 113 页,共 3346 部动作片电影的数据(本来不止这些的,但是有一些电影没有提供下载链接,我在 excel 中排序后直接手动剔除了)。

详解Python爬取并下载《电影天堂》3千多部电影

 详解Python爬取并下载《电影天堂》3千多部电影

然后想看什么电影的话,直接复制这些电影下载的磁力链接,到迅雷里面下载就好啦。 

四、爬虫程序的一些小优化

1. 在网站提供的下载链接中,我试了一下,发现 magnet 开头的这类链接放在迅雷中可以直接下载,而 ftp 开头的链接在迅雷中总显示资源获取失败(我不知道是不是我打开的方式不对,反正就是下载不来),于是我对程序做了一些小的调整,使其只获取 magnet 这类的链接。

修改的方式也很简单,只需要调整 网页解析函数 即可(爬虫的五个部分是相对独立的,修改时只需调整相应的模块即可,其余部分无需修改)。

def parse_data(html):
  '''
  功能:提取 html 页面信息中的关键信息,并整合一个数组并返回
  参数:html 根据 url 获取到的网页内容
  返回:存储有 html 中提取出的关键信息的数组
  '''
  bsobj = bs4.BeautifulSoup(html,'html.parser')
  info = []
  
  # 获取表头信息
  tbList = bsobj.find_all('table', attrs = {'class': 'tbspan'})
  
  for item in tbList:
    movie = []
    link = item.b.find_all('a')[1]
    name = link["title"]
    url = 'https://www.dy2018.com' + link["href"]
    
    try:
      # 查找电影下载的磁力链接
      temp = bs4.BeautifulSoup(get_data(url),'html.parser')
      tbody = temp.find_all('tbody')
      
      for i in tbody:
        download = i.a.text
        if 'magnet:?xt=urn:btih' in download:
          movie.append(name)
          movie.append(url)
          movie.append(download)
          #print(movie)
          info.append(movie)
          break
    except Exception as e:
      print(e)
  
  return info

注意代码 26 行处,我加了一个 if 语句的判断,如果下载链接中包含 magnet:?xt=urn:btih 字符串,则视为有效链接,下载下来,否则跳过。

2. 我一直在想能不能有个办法让迅雷一键批量下载我们爬到的电影。使用 python 操纵第三方的软件,这其实挺难的。不过后来找到了一种方法,也算是解决了这个问题。

就是我们发现迅雷软件启动后,会自动检测我们的剪切板,只要我们复制了下载链接,它便会自动弹出下载的提示框。借助这个思路,我们可以使用代码,将下载的链接复制进入剪切板,等下载框自动出现后,手动确认开始下载(这是我目前想到的最好的办法了,不知道各位大佬有没有更好的思路,欢迎指导交流)。

import pyperclip
import os
import pandas as pd
 
imageData = pd.read_csv("Data/电影天堂/动作片2.csv",names=['name','link','download'],encoding = 'gbk')
# 获取电影的下载链接,并用换行符分隔
a_link = imageData['download']
links = '\n'.join(a_link)
 
# 复制到剪切板
pyperclip.copy(links);
print('已粘贴');
 
# 打开迅雷
thunder_path = r'D:\Program Files (x86)\Thunder Network\Thunder9\Program\Thunder.exe'
os.startfile(thunder_path)

亲测可以实现,但是。。。不建议尝试(你能想象迅雷打开的一瞬间创建几百个下载任务的场景吗?反正我的电脑是缓了好久好久才反应过来)。大家还是老老实实的,手动复制链接下载吧(csv文件可以用 excel 打开,竖着选中一列,然后复制,也能达到相同的效果) ,这种骚操作太蠢了还是不要试了。

写在后面的话

???锣碌男戳撕枚啵?膊恢?拦丶?奈侍饨睬宄?嗣挥小S心睦锩唤睬宄??蛘吣睦锝驳牟缓鲜实幕埃?队??拧?br />  其实吧,写文章,写博客,写教程,都是一个知识重新熔炼内化的过程,在写这篇博客的时候,我也一直在反复审视我学习爬虫的过程,以及我爬虫代码一步步的变化,从一开始的所有代码全部揉在主函数中,到后来把一些变动较少的功能提取出来,写成单独的函数,再到后来形成基本稳定的五大部分。

以至于在我后来学习使用 scrapy 框架时候,惊人的发现 scrapy 框架的结构跟我的爬虫结构有着异曲同工之妙,我的这个相当于是一个简易版的爬虫框架了,纯靠自己摸索达到这个效果,我感觉还是挺有成就感的。

以上所述是小编给大家介绍的Python爬取并下载《电影天堂》3千多部电影详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
python列表去重的二种方法
Feb 14 Python
Python使用multiprocessing实现一个最简单的分布式作业调度系统
Mar 14 Python
python3+PyQt5+Qt Designer实现扩展对话框
Apr 20 Python
python绘制圆柱体的方法
Jul 02 Python
Pycharm取消py脚本中SQL识别的方法
Nov 29 Python
python实现趣味图片字符化
Apr 30 Python
Python运行异常管理解决方案
Mar 09 Python
django实现将后台model对象转换成json对象并传递给前端jquery
Mar 16 Python
使用tensorflow根据输入更改tensor shape
Jun 23 Python
Python实时监控网站浏览记录实现过程详解
Jul 14 Python
Django开发RESTful API实现增删改查(入门级)
May 10 Python
使用Pytorch训练two-head网络的操作
May 28 Python
Python 2/3下处理cjk编码的zip文件的方法
Apr 26 #Python
实例详解Matlab 与 Python 的区别
Apr 26 #Python
Python生成MD5值的两种方法实例分析
Apr 26 #Python
十个Python练手的实战项目,学会这些Python就基本没问题了(推荐)
Apr 26 #Python
Python生成rsa密钥对操作示例
Apr 26 #Python
python利用Opencv实现人脸识别功能
Apr 25 #Python
Python OpenCV利用笔记本摄像头实现人脸检测
Aug 20 #Python
You might like
解析php中反射的应用
2013/06/18 PHP
浅析PHP安装扩展mcrypt以及相关依赖项(PHP安装PECL扩展的方法)
2013/07/05 PHP
PHP获取当前url的具体方法全面解析
2013/11/26 PHP
Yii2基于Ajax自动获取表单数据的方法
2016/08/10 PHP
javascript 播放器 控制
2007/01/22 Javascript
JavaScript 字符编码规则
2009/05/04 Javascript
Javascript 获取滚动条位置等信息的函数
2009/09/08 Javascript
使用jquery读取html5 localstorage的值的方法
2013/01/04 Javascript
jquery的冒泡事件的阻止与允许(三种实现方法)
2013/02/01 Javascript
使用JQuery实现的分页插件分享
2015/11/05 Javascript
vue基于Vue2.0和高德地图的地图组件实例
2017/04/28 Javascript
js 奇葩技巧之隐藏代码
2017/08/11 Javascript
浅谈mint-ui 填坑之路
2017/11/06 Javascript
深入理解Node module模块
2018/03/26 Javascript
详解Angular中通过$location获取地址栏的参数
2018/08/02 Javascript
vue的style绑定background-image的方式和其他变量数据的区别详解
2018/09/03 Javascript
详解Vue内部怎样处理props选项的多种写法
2018/11/06 Javascript
iview实现select tree树形下拉框的示例代码
2018/12/21 Javascript
简单通过settimeout看javascript的运行机制
2019/05/10 Javascript
jQuery实现图片下载代码
2019/07/18 jQuery
在Node.js中将SVG图像转换为PNG,JPEG,TIFF,WEBP和HEIF格式的方法
2019/08/22 Javascript
vue实现给div绑定keyup的enter事件
2020/07/31 Javascript
微信小程序wx.getUserInfo授权获取用户信息(头像、昵称)的实现
2020/08/19 Javascript
[09:37]2018DOTA2国际邀请赛寻真——不懈追梦的Team Serenity
2018/08/13 DOTA
Python流程控制 if else实现解析
2019/09/02 Python
Python中Selenium库使用教程详解
2020/07/23 Python
套娃式文件夹如何通过Python批量处理
2020/08/23 Python
乔丹诺(Giordano)酒庄德国官网:找到最好的意大利葡萄酒
2017/12/28 全球购物
北美个性化礼品商店:Things Remembered
2018/06/12 全球购物
ManoMano英国:欧洲第一家专注于DIY和园艺市场的电商平台
2020/03/12 全球购物
广告学专业毕业生自荐信
2014/05/28 职场文书
欢度春节标语
2014/07/01 职场文书
2014年党员教师自我剖析材料
2014/09/30 职场文书
2014年大学班长工作总结
2014/11/14 职场文书
公共场所卫生管理制度
2015/08/05 职场文书
ubuntu如何搭建vsftpd服务器
2022/12/24 Servers