社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

腾讯视频 Python 爬虫项目实战

编程派 • 6 年前 • 438 次点击  

文 | yangrq1018 编辑 | EarlGrey

推荐 | 编程派公众号(ID:codingpy)

做了一些小项目,用的技术和技巧会比较散比较杂,写一个小品文记录一下,帮助熟悉。

需求:经常在腾讯视频上看电影,在影片库里有一个"豆瓣好评"板块。我一般会在这个条目下面挑电影。但是电影很多,又缺乏索引,只能不停地往下来,让js加载更多的条目。然而前面的看完了,每次找新的片就要拉很久。所以用爬虫将"豆瓣好评"里的电影都爬下来整理到一个表中,方便选片。

项目地址:https://github.com/yangrq1018/vqq-douban-film

依赖

需要如下Python包:

  • requests

  • bs4 - Beautiful soup

  • pandas

就这些,不需要复杂的自动化爬虫架构,简单而且常用的包就够了。

爬取影片信息

首先观察电影频道,发现是异步加载的。可以用Firefox(Chrome也行)的inspect中的network这个tab来筛选查看可能的api接口。很快发现接口的URL是这个格式的:

  1. base_url = 'https://v.qq.com/x/bu/pagesheet/list?_all=1&append=1&channel=movie&listpage=2&offset={offset}&pagesize={page_size}&sort={sort}'

其中 offset是请求页开始的位置, pagesize是每页请求的数量, sort是类型。在这里 sort=21指我们需要的"豆瓣好评"类型。 pagesize不能大于30,大于30也只会返回三十个元素,低于30会返回指定数量的元素。

  1. # 让Pandas完整到处过长的URL,后面会需要

  2. pd.set_option('display.max_colwidth', -1)


  3. base_url = 'https://v.qq.com/x/bu/pagesheet/list?_all=1&append=1&channel=movie&listpage=2&offset={offset}&pagesize={page_size}&sort={sort}'


  4. # 豆瓣最佳类型

  5. DOUBAN_BEST_SORT = 21


  6. NUM_PAGE_DOUBAN = 167

写一个小小的循环就可以发现,豆瓣好评这个类型总共有167页,每页三十个元素。

我们使用 requests这个库来请求网页, get_soup会请求第 page_idx页的元素,用 Beautifulsoup来解析 response.content,生成一个类似 DOM,可以很方便地查找我们需要的element的对象。我们返回一个 list。每个电影条目是包含在一个叫list_item的 div里的,所以写一个函数来帮助我们提取所有的这样的 div

  1. def get_soup(page_idx, page_size=30, sort=DOUBAN_BEST_SORT):

  2. url = base_url.format(offset=page_idx * page_size, page_size=page_size, sort=sort)

  3. res = requests. get(url)

  4. soup = bs4.BeautifulSoup(res.content.decode('utf-8'), 'lxml')

  5. return soup


  6. def find_list_items(soup):

  7. return soup.find_all('div', class_='list_item')

我们遍历每一页,返回一个含有所有的被 bs4过的条目元素的HTML的 list

  1. def douban_films():

  2. rel = []

  3. for p in range(NUM_PAGE_DOUBAN):

  4. print('Getting page {}'.format(p))

  5. soup = get_soup(p)

  6. rel += find_list_items(soup)

  7. return rel

这是其中的一部电影的HTML代码:

  1. __wind="" class="list_item">
  2. class="figure" data-float="j3czmhisqin799r" href="https://v.qq.com/x/cover/j3czmhisqin799r.html" tabindex="-1" target="_blank" title="霸王别姬">

  3. alt="霸王别姬" class="figure_pic" onerror= "picerr(this,'v')" src="//puui.qpic.cn/vcover_vt_pic/0/j3czmhisqin799rt1444885520.jpg/220"/>

  4. alt="VIP" class="mark_v" onerror="picerr(this)" src="//i.gtimg.cn/qqlive/images/mark/mark_5.png" srcset="//i.gtimg.cn/qqlive/images/mark/mark_5@2x.png 2x"/>

  5. class="figure_caption">

  6. class="figure_score">9.6

  7. class= "figure_detail figure_detail_two_row">
  8. class="figure_title figure_title_two_row bold" href="https://v.qq.com/x/cover/j3czmhisqin799r.html" target="_blank" title="霸王别姬">霸王别姬

  9. class="figure_desc" title="主演:张国荣 张丰毅 巩俐 葛优">主演:张国荣 张丰毅 巩俐 葛优

  • class="figure_count"> class="svg_icon svg_icon_play_sm" height="16" viewbox="0 0 16 16" width="16"> xlink:href ="#svg_icon_play_sm">4671万

  • 不难发现,霸王别姬这部电影,名称、播放地址、封面、评分、主演,是否需要会员和播放量都在这个 div中。在ipython这样的interactive环境中,可以方便地找出怎么用bs来提取他们的方法。我试用的一个技巧是,可以打开一个 spyder.py文件,在里面编写需要的函数,将ipython的自动重载模组的选项打开,然后就可以在console里debug之后将代码复制到文件里,然后ipython中的函数也会相应的更新。这样的好处是会比在ipython中改动代码方便许多。具体如何打开ipython的自动重载:

    1. %load_ext autoreload

    2. %autoreload 2 # Reload all modules every time before executing Python code

    3. %autoreload 0 # Disable automatic reloading

    这个 parse_films函数用bs中的两个常用方法提取信息:

    • find

    • find_all

    因为豆瓣的API已经关闭了检索功能,爬虫又会被反爬虫检测到,本来想检索到豆瓣的评分添加上去这个功能就放弃了。

    OrderedDict可以接受一个由(key, value)组成的list,然后key的顺序会被记住。这个在之后我们导出为pandas DataFrame的时候很有用。

    1. def parse_films(films):

    2. '''films is a list of `bs4.element.Tag` objects'''

    3. rel = []

    4. for i, film in enumerate(films):

    5. title = film.find('a', class_="figure_title")['title']

    6. print('Parsing film %d: ' % i, title)

    7. link = film.find('a', class_="figure")['href']

    8. img_link = film.find('img', class_="figure_pic")['src']


    9. # test if need VIP

    10. need_vip = bool(film.find('img', class_="mark_v"))

    11. score = getattr(film.find('div', class_='figure_score'), 'text', None )

    12. if score: score = float(score)

    13. cast = film.find('div', class_="figure_desc")

    14. if cast:

    15. cast = cast.get('title', None)

    16. play_amt = film.find('div', class_="figure_count").get_text()


    17. # db_score, db_link = search_douban(title)

    18. # Store key orders

    19. dict_item = OrderedDict([

    20. ('title', title),

    21. ('vqq_score', score),

    22. # ('db_score', db_score),

    23. ('need_vip', need_vip),

    24. ('cast', cast),

    25. ('play_amt', play_amt),

    26. ('vqq_play_link', link),

    27. # ('db_discuss_link', db_link),

    28. ('img_link', img_link),

    29. ])


    30. rel.append(dict_item)


    31. return rel

    导出

    最后,我们调用写好的函数,在主程序中运行。

    被解析好,list of dictionaries格式的对象,可以直接传给DataFrame的constructor。按照评分排序,最高分在前面,然后将播放链接转换成HTML的链接标签,更加美观而且可以直接打开。

    注意,pandas生成的csv文件一直和excel有兼容性问题,在有中文字符的时候会乱码。解决方法是选择utf_8_sig这个encoding,就可以让excel正常解码了。

    Pickle是一个Python十分强大的serialization库,可以保存Python的对象为文件,再从文件中加载Python的对象。我们将我们的DataFrame保存为 .pkl。调用 DataFrame to_html方法保存一个HTML文件,注意要将 escape 设置为False不然超链接不能被直接打开。

    1. if __name__ == '__main__':

    2. df = DataFrame(parse_films(douban_films()))

    3. # Sorted by score

    4. df.sort_values(by="vqq_score", inplace=True, ascending=False)

    5. # Format links

    6. df['vqq_play_link'] = df['vqq_play_link'].apply(lambda x: 'Film link'.format(x))

    7. df['img_link'] = df['img_link'].apply(lambda x: ''.format(x))


    8. # Chinese characters in Excel must be encoded with _sig

    9. df.to_csv('vqq_douban_films.csv', index=False, encoding='utf_8_sig')

    10. # Pickle

    11. df.to_pickle('vqq_douban_films.pkl')

    12. # HTML, render hyperlink

    13. df.to_html('vqq_douban_films.html', escape=False)

    项目管理

    代码部分就是这样。那么写完了代码,就要把它归档保存,也便于分析。选择放在Github上。

    那么,其实Github是提供了一个命令行工具的(不是 git,是 git的一个扩展),叫做 hub。macOS用户可以这样安装

    1. brew install hub

    hub有许多比 git更简练的语法,我们这里主要用

    1. hub create -d "Create repo for our proj" vqq-douban-film

    来直接从命令行创建repo,是不是很酷!根本不用打开浏览器。然后可能会被提示在Github上登记一个你的SSH公钥(验证权限),如果没有的话用 ssh-keygen生成一个就好了,在Github的设置里把 .pub的内容复制进去。

    项目目录里,可能会有 __pycache__.DS_Store这样你不想track的文件。手写一个 .gitignore又太麻烦,有没有工具呢,肯定有的!Python有一个包

    1. pip install git-ignore

    2. git-ignore python # 产生一个python的template

    3. # 手动把.DS_Store加进去

    只用命令行,装逼装到爽。

    来源:https://segmentfault.com/a/1190000019421255

    回复下方「关键词」,获取优质资源


    回复关键词「 pybook03」,立即获取主页君与小伙伴一起翻译的《Think Python 2e》电子版

    回复关键词「pybooks02」,立即获取 O'Reilly 出版社推出的免费 Python 相关电子书合集

    回复关键词「书单02」,立即获取主页君整理的 10 本 Python 入门书的电子版



    印度小伙写了套深度学习教程,Github上星标已经5000+

    GitHub热榜第四!这套Python机器学习课,免费获取还易吸收

    《流畅的 Python》到底好在哪?

    如何系统化学习 Python ?

    GitHub标星2.6万!Python算法新手入门大全

    使用 Vue.js 和 Flask 实现全栈单页面应用

    Python 实现一个自动化翻译和替换的工具

    使用 Python 制作属于自己的 PDF 电子书

    12步轻松搞定Python装饰器

    200 行代码实现 2048 游戏

    题图:pexels,CC0 授权。

    Python社区是高质量的Python/Django开发社区
    本文地址:http://www.python88.com/topic/34376
     
    438 次点击