Python学习笔记---豆瓣电影爬虫记

豆瓣是个好网站,能学习各种知识、能社交、能找房子、找驴友等。

于我而言,最大的快乐在于豆瓣能提供丰富的在线数据,如:书/电影/音乐等,不仅有这些的基础数据,还有各种榜单/评论等,数据结构也相当丰富。在本人最开始写前端的时候,曾在网上寻找各种在线数据来进行页面的渲染,直到后面找到豆瓣的时候发现竟然还有官方的API提供,可畏业界良心。后面学习各种框架都是界面参考豆瓣,数据直接用API获取,方便得不行。后面学习小程序的时候,也想用直接用豆瓣的API,发现小程序直接调用的时候会出现403(好像跟小程序的UA有关系),后面自己本地起了nginx做了代理就ok了。最近想学点新东西,突然想先去看看豆瓣的API文档,结果发现网站打不开了,所有的api都关掉了。那正好,就学Python吧,我记得我第一次听说Python好像爬虫很厉害,那就试试吧。

之前有看过一些基本的语法,贴上几个网站 官方中文文档, runoob.com-超全的学习网站


  • 环境准备(Mac) 其它环境安装教程

Mac和Linux最新版好像都带自带了python,我自己是Mac,所以用试了一下:

python
默认python版本.png

可以看出默认的python是2.7.16,目前最新版本是3.x。
退出,狂按Command + C,发现没反应,再输入exit,结果提示

>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit

原来python命令的退出方式跟其它的脚本不一样呀,Mac上为 command+d 或者 输入exit() 加回车。
之前看的文档上有提过,可以使用python3来使用最新版本的python,试了一下:


pyhtone3.png

Mac也内置了python3.7.3,目前官方最新版本为3.8.2,还是比较新的,可能由于我的Mac OS是最新版的原因吧。
python跟node/java一样,安装完环境之后可以直接在命令行里面运行一些简单的指令,如下:


简单python交互.png

说明:
print()是打印语句,类似于console()等。
其中有一句print("2+3=", 2+3), 在print()方法中可以进行简单的运算。
in = input(); print("输入的是:"+ in);
    in = input(); print("输入的是:"+ in);
 ^
SyntaxError: invalid syntax // 这里出错,是因为in是一个关键字,不能用来定义变量

python的其它语法就需要在上面我贴的两个网址去学习哈。

上面演示的是在命令行运行简单代码,Python也支持以文件的方式运行。
后面我用vs code来进行开发。

  • 爬虫实战
    新建一个test.py文件,里面可以写上
print('my first py program ')

然后,在vs 的termial里面运行 test.py,记得在运行之后要保存文件哦。

python3 test.py
my first py program

ok,这样我们就知道怎么用一个文件去执行我们写的python代码了。

接下来,我们先分析一下豆瓣电影(top250)爬虫的需求:

  1. 最终的数据结构:json格式,方便传输与转换。
单一电影的数据结构,最后生成一个list
{'ranking': '25', 'title': '触不可及', 'orther_title': '/闪亮人生(港)  /  逆转人生(台)', 'director': ' 奥利维·那卡什 Olivier Nakache / 艾力克·托兰达 Eric Toledano', 'year': '2011', 'region': '剧情 喜剧', 'douban_href': 'https://movie.douban.com/subject/6786002/', 'average_rating': '9.2', 'votes': '684449', 'short_quote': '满满温情的高雅喜剧。'}
  1. 数据源网址:豆瓣电影 Top 250
    爬虫的大致原理是:用http方法获取到源网址的整体dom结构,然后根据正则表达式来进行匹配,最终过滤出想要的数据。
    所以我们先去源网站观察一下dom结构,

    电影榜单dom对照.png

    我们需要的数据,是包含在一个
      标签对里面,而且经过搜索可以发现,整个dom树里面只含有一个
        标签对。
        我们知道了dom的结构,就可以将我们所需要的数据一一拆解出来了。
        这样我们的需求就清楚了,接下来就要看怎么具体实现了。

      1. 先让我们的程序可以访问到源网址,https://movie.douban.com/top250

      # test.py
      # print('my first py program')
      # 1、引入需要要的包  
      # 网络请求相关的包
      from urllib.request import urlopen, Request
      import ssl
      # 正则相关的包
      import re
      # 配置https请求
      ssl._create_default_https_context = ssl._create_unverified_context 
      # 设置数据源地址
      source_url = 'https://movie.douban.com/top250'
      # 自定义http request请求头,豆瓣默认只允许部分UA进行访问 这里自定义User-Agent成浏览器的UA
      custom_headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
      # 初始化Request
      movie_request = Request(source_url, headers = custom_headers)
      # 发出request请求
      movie_response = urlopen(movie_request)
      # 将读取结果进行utf-8解码,避免乱码
      html = movie_response.read().decode('utf-8')
      # 测试打印结果        
      print(html)
      

      我们在termial里面运行代码,可以看到正常的打印结果,如下图:


      获取源网址返回的结果.png

      这是整个页面的dom结果,这个效果和我们在浏览器里面通过右键>显示网页源代码所看到的内容是一致的。

      1. 接下来,我们将所需要的
          标签对里面的内容从完整的dom树里面匹配出来,并保存至一个本地文件里面。
          我们先看一下单个电影数据在dom中的结构是什么样的。
      2. 8 辛德勒的名单

        导演: 史蒂文·斯皮尔伯格 Steven Spielberg   主演: 连姆·尼森 Liam Neeson...
        1993 / 美国 / 剧情 历史 战争

        9.5 753795人评价

        拯救一个人,就是拯救整个世界。

      3. 单个电影是包含在

      4. 标签对里面的,而
          里面含有多个
        1. 标签对,所以首先要把这些
        2. 标签对一个个的匹配出来,然后写到本地文件中。
          具体代码如下:

          # 定义一个函数,获取所有跟电影相关的
        3. def getMovieItems(content): # 匹配正则表达式 [\s\n]*表示,在
        4. 标签和
        5. 运行程序, python3 test.py,可以看到下图的结果:

          25条电影数据匹配结果.png

          我们打印了匹配后的数组,以及数组长度25。 由于250条数据量太大,默认一页只显示25条,我们暂且先看这25条的数据,后面可以增加分页参数,获取剩下的数据。

          ok,到这里我们就已经获取到我们所需要的电影数据源,我们要在此基础上进行数据匹配:

          # 定义一个列表,用来存最终数据
          list = []
          # 循环遍历
          for m in movies:
              # 删除掉     
              m = re.sub(' ', '', m)
              dic = {}
              # 评分
              reg = '(.*)'
              ranking = re.findall(re.compile(reg), m)
              print(ranking)
              dic['ranking'] = ranking[0]
          
              # title
              reg = '(.*)'
              title = re.findall(re.compile(reg), m)
              print(title)
              dic['title'] = title[0]
          
              # orther_title
              reg = '(.*)'
              orther_title = re.findall(re.compile(reg), m)
              print(orther_title)
              dic['orther_title'] = orther_title[0]
          
              # type_people  导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim Robbins /...
          1994 / 美国 / 犯罪 剧情 reg = r'

          (.*?)

          ' type_people = re.findall(re.compile(reg, re.S), m)[0] # 删除掉   type_people = re.sub(' ', '', type_people) # 删除掉
          ; type_people = re.sub('
          ', '', type_people) # 删除掉 回车/换行符; type_people = re.sub('\n', '', type_people) # 删除掉 空格; type_people = re.sub('\s', '', type_people) print('type_people', type_people) # director 导演 匹配导演: 与 主演之前的内容 有些可能没有主演的演字... reg = r'导演:(.*)主' director = re.findall(re.compile(reg, re.S), type_people) print(director) dic['director'] = director[0] # year 年份 匹配4位数字 reg = r'\d+' year = re.findall(re.compile(reg), type_people) print(year) dic['year'] = year[0] # actors 主演 从主演: 开始 截取至 4位年份止 reg = r'主演:(.*)\d{4}' director = re.findall(re.compile(reg), type_people) print(director) if (len(director)): dic['director'] = director[0] # region 国家 从4位年份+'/'截取至下一个'/' reg = r'\d{4}/(.*)/' region = re.findall(re.compile(reg), type_people) print(region) if (len(region)): dic['region'] = region[0] # type 类型 reg = r'\d{4}/.*/(.*)' region = re.findall(re.compile(reg), type_people) print(region) if (len(region)): dic['region'] = region[0] # douban_href reg = r'' douban_href = re.findall(re.compile(reg, re.S), m) print(douban_href) dic['douban_href'] = douban_href[0] # average_rating reg = '(.*?)' average_rating = re.findall(re.compile(reg), m) print(average_rating) dic['average_rating'] = average_rating[0] # votes 1944072人评价 reg = '(.*)人评价' votes = re.findall(re.compile(reg), m) print(votes) dic['votes'] = votes[0] # short_quote reg = '(.*)' short_quote = re.findall(re.compile(reg, re.S), m) print(short_quote) dic['short_quote'] = short_quote[0] list.append(dic) print(list)

          我们执行python3 test.py,就可以看到结果:


          最终电影数组.png

          这样,我们就已经获取到了完整的25条电影数据了,接下来,我们可以将这些数据写入到本地文件,可以拿来给别人分享或者在其它程序里面用啦,具体代码如下:

          import json
          
          json_str = json.dumps(list,  indent=4, ensure_ascii=False)
          json_file = open('movie-douban-top250.json', 'w+')
          json_file.writelines(json_str)
          

          可以直接写在代码最后面,运行之后在test.py同级目录会生成一个movie-douban-top250.json的文件,如下图所示:


          最终完整的json文件.png

          好了,到此我们已经完整的实现了之前的需求,获取原网址的电影数据,并生成了一个本地的json文件。

          写代码的过程中查询了很多文章(感谢万能的bing...),花了好长时间才写完,写文章的时候又花了好几个小时,真心不容易。

          最后,贴上完整的代码,大家可以下载试试哦。
          https://github.com/realfly08/learn-python/blob/master/test.py

          觉得可以的话,请点个赞哦!

          你可能感兴趣的:(Python学习笔记---豆瓣电影爬虫记)