Python3 爬虫实战 — 豆瓣电影TOP250【requests、Xpath、正则表达式、CSV、二进制数据储存】


  • 爬取时间:2019-09-27
  • 爬取难度:★★☆☆☆☆
  • 请求链接:https://movie.douban.com/top250 以及每部电影详情页
  • 爬取目标:爬取榜单上每一部电影详情页的数据,保存为 CSV 文件;下载所有电影海报到本地
  • 涉及知识:请求库 requests、解析库 lxml、Xpath 语法、正则表达式、CSV 和二进制数据储存、列表操作
  • 完整代码:https://github.com/TRHX/Python3-Spider-Practice/tree/master/BasicTraining/douban-top250
  • 其他爬虫实战代码合集(持续更新):https://github.com/TRHX/Python3-Spider-Practice
  • 爬虫实战专栏(持续更新):https://itrhx.blog.csdn.net/article/category/9351278

文章目录

  • 【1x00】循环爬取网页模块
  • 【2x00】解析模块
    • 【2x01】Xpath 解析排名、电影名、评分信息
    • 【2x02】Xpath 解析参评人数
    • 【2x03】正则表达式解析制片国家、语言
  • 【3x00】返回解析数据
  • 【4x00】数据储存模块
  • 【5x00】完整代码
  • 【6x00】数据截图
  • 【7x00】程序不足的地方


【1x00】循环爬取网页模块

观察豆瓣电影 Top 250,请求地址为:https://movie.douban.com/top250

每页展示25条电影信息,照例翻页观察 url 的变化:

第一页:https://movie.douban.com/top250

第二页:https://movie.douban.com/top250?start=25&filter=

第三页:https://movie.douban.com/top250?start=50&filter=

一共有10页,每次改变的是 start 的值,利用一个 for 循环,从 0 到 250 每隔 25 取一个值拼接到 url,实现循环爬取每一页,由于我们的目标是进入每一部电影的详情页,然后爬取详情页的内容,所以我们可以使用 Xpath 提取每一页每部电影详情页的 URL,将其赋值给 m_urls,并返回 m_urlsm_urls 是一个列表,列表元素就是电影详情页的 URL

def index_pages(number):url = 'https://movie.douban.com/top250?start=%s&filter=' % numberindex_response = requests.get(url=url, headers=headers)tree = etree.HTML(index_response.text)m_urls = tree.xpath("//li/div/div/a/@href")return m_urlsif __name__ == '__main__':for i in range(0, 250, 25):movie_urls = index_pages(i)

【2x00】解析模块

定义一个解析函数 parse_pages(),利用 for 循环,依次提取 index_pages() 函数返回的列表中的元素,也就是每部电影详情页的 URL,将其传给解析函数进行解析

def index_pages(number):expressionsdef parse_pages(url):expressionsif __name__ == '__main__':for i in range(0, 250, 25):movie_urls = index_pages(i)for movie_url in movie_urls:results = parse_pages(movie_url)

详细看一下解析函数 parse_pages(),首先要对接收到的详情页 URL 发送请求,获取响应内容,然后再使用 Xpath 提取相关信息

def parse_pages(url):movie_pages = requests.get(url=url, headers=headers)parse_movie = etree.HTML(movie_pages.text)

【2x01】Xpath 解析排名、电影名、评分信息

其中排名、电影名和评分信息是最容易匹配到的,直接使用 Xpath 语法就可以轻松解决:

# 排名
ranking = parse_movie.xpath("//span[@class='top250-no']/text()")# 电影名
name = parse_movie.xpath("//h1/span[1]/text()")# 评分
score = parse_movie.xpath("//div[@class='rating_self clearfix']/strong/text()")

【2x02】Xpath 解析参评人数

接下来准备爬取有多少人参与了评价,分析一下页面:
01
如果只爬取这个 <span> 标签下的数字的话,没有任何提示信息,别人看了不知道是啥东西,所以把 人评价 这三个字也爬下来的话就比较好了,但是可以看到数字和文字不在同一个元素标签下,而且文字部分还有空格,要爬取的话就要把 class="rating_people"a 标签下所有的 text 提取出来,然后再去掉空格:

# 参评人数
# 匹配a节点
value = parse_movie.xpath("//a[@class='rating_people']")
# 提取a节点下所有文本
string = [value[0].xpath('string(.)')]
# 去除多余空格
number = [a.strip() for a in string]# 此时 number = ['1617307人评价']

这样做太麻烦了,我们可以直接提取数字,得到一个列表,然后使用另一个带有提示信息的列表,将两个列表的元素合并,组成一个新列表,这个新列表的元素就是提示信息+人数

# 参评人数
value = parse_movie.xpath("//span[@property='v:votes']/text()")
# 合并元素
number = [" ".join(['参评人数:'] + value)]# 此时 number = ['参评人数:1617307']

【2x03】正则表达式解析制片国家、语言

接下来尝试爬取制片国家/地区、语言等信息:
02
分析页面可以观察到,制片国家/地区和语言结构比较特殊,没有特别的 class 或者 id 属性,所包含的层次关系也太复杂,所以这里为了简便,直接采用正则表达式来匹配信息,就没有那么复杂了:

# 制片国家/地区
value = re.findall('<span class="pl">制片国家/地区:</span>(.*?)<br/>', movie_pages.text)
country = [" ".join(['制片国家:'] + value)]# 语言
value = re.findall('<span class="pl">语言:</span>(.*?)<br/>', movie_pages.text)
language = [" ".join(['语言:'] + value)]

【3x00】返回解析数据

其他剩下的信息皆可利用以上方法进行提取,所有信息提取完毕,最后使用 zip() 函数,将所有提取的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表

return zip(ranking, name, score, number, types, country, language, date, time, other_name, director, screenwriter, performer, m_url, imdb_url)

【4x00】数据储存模块

定义一个数据保存函数 save_results()

def save_results(data):with open('douban.csv', 'a', encoding="utf-8-sig") as fp:writer = csv.writer(fp)writer.writerow(data)

注意:编码方式要设置为 utf-8-sig,如果设置为 utf-8,则文件会乱码,不设置编码,则可能会报一下类似错误:

UnicodeEncodeError: 'gbk' codec can't encode character '\ub3c4' in position 9: illegal multibyte sequence

可以看到错误出现在 \ub3c4 上,将该 Unicode 编码转换为中文为 ,发现正是排名第 19 的电影:熔炉 도가니,因为标题有韩文,所以在储存为 CSV 文件时会报编码错误,而将编码设置为 utf-8-sig 就不会报错,具体原因参见:《Python 中文日文汉字乱码处理utf-8-sig》

接下来是保存电影的海报到本地:

# 保存电影海报
poster = parse_movie.xpath("//div[@id='mainpic']/a/img/@src")
response = requests.get(poster[0])
name2 = re.sub(r'[A-Za-z\:\s]', '', name[0])
poster_name = str(ranking[0]) + ' - ' + name2 + '.jpg'
dir_name = 'douban_poster'
if not os.path.exists(dir_name):os.mkdir(dir_name)
poster_path = dir_name + '/' + poster_name
with open(poster_path, "wb")as f:f.write(response.content)

解析电影详情页,使用 Xpath 提取海报的 URL,向该 URL 发送请求

图片以 排名+电影名.jpg 的方式命名,但是由于提取的电影名部分含有特殊字符,比如排名第 10 的电影:忠犬八公的故事 Hachi: A Dog’s Tale,其中有个冒号,而 Windows 文件命名是不能包含这些字符的,所以我们直接去除电影名包含的英文字符、空白字符、特殊字符,只留下中文,代码实现: name2 = re.sub(r'[A-Za-z\:\s]', '', name[0])

定义一个文件夹名称 douban_poster,利用 os 模块判断当前是否存在该文件夹,若不存在就创建一个

最后以二进制形式保存海报到当前目录的 douban_poster 文件夹下


【5x00】完整代码

# =============================================
# --*-- coding: utf-8 --*--
# @Time    : 2019-09-27
# @Author  : TRHX
# @Blog    : www.itrhx.com
# @CSDN    : https://blog.csdn.net/qq_36759224
# @FileName: douban.py
# @Software: PyCharm
# =============================================import requests
from lxml import etree
import csv
import re
import time
import osheaders = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'}def index_pages(number):url = 'https://movie.douban.com/top250?start=%s&filter=' % numberindex_response = requests.get(url=url, headers=headers)tree = etree.HTML(index_response.text)m_urls = tree.xpath("//li/div/div/a/@href")return m_urlsdef parse_pages(url):movie_pages = requests.get(url=url, headers=headers)parse_movie = etree.HTML(movie_pages.text)# 排名ranking = parse_movie.xpath("//span[@class='top250-no']/text()")# 电影名name = parse_movie.xpath("//h1/span[1]/text()")# 评分score = parse_movie.xpath("//div[@class='rating_self clearfix']/strong/text()")# 参评人数value = parse_movie.xpath("//span[@property='v:votes']/text()")number = [" ".join(['参评人数:'] + value)]# value = parse_movie.xpath("//a[@class='rating_people']")# string = [value[0].xpath('string(.)')]# number = [a.strip() for a in string]# print(number)# 类型value = parse_movie.xpath("//span[@property='v:genre']/text()")types = [" ".join(['类型:'] + value)]# 制片国家/地区value = re.findall('<span class="pl">制片国家/地区:</span>(.*?)<br/>', movie_pages.text)country = [" ".join(['制片国家:'] + value)]# 语言value = re.findall('<span class="pl">语言:</span>(.*?)<br/>', movie_pages.text)language = [" ".join(['语言:'] + value)]# 上映时期value = parse_movie.xpath("//span[@property='v:initialReleaseDate']/text()")date = [" ".join(['上映日期:'] + value)]# 片长value = parse_movie.xpath("//span[@property='v:runtime']/text()")time = [" ".join(['片长:'] + value)]# 又名value = re.findall('<span class="pl">又名:</span>(.*?)<br/>', movie_pages.text)other_name = [" ".join(['又名:'] + value)]# 导演value = parse_movie.xpath("//div[@id='info']/span[1]/span[@class='attrs']/a/text()")director = [" ".join(['导演:'] + value)]# 编剧value = parse_movie.xpath("//div[@id='info']/span[2]/span[@class='attrs']/a/text()")screenwriter = [" ".join(['编剧:'] + value)]# 主演value = parse_movie.xpath("//div[@id='info']/span[3]")performer = [value[0].xpath('string(.)')]# URLm_url = ['豆瓣链接:' + movie_url]# IMDb链接value = parse_movie.xpath("//div[@id='info']/a/@href")imdb_url = [" ".join(['IMDb链接:'] + value)]# 保存电影海报poster = parse_movie.xpath("//div[@id='mainpic']/a/img/@src")response = requests.get(poster[0])name2 = re.sub(r'[A-Za-z\:\s]', '', name[0])poster_name = str(ranking[0]) + ' - ' + name2 + '.jpg'dir_name = 'douban_poster'if not os.path.exists(dir_name):os.mkdir(dir_name)poster_path = dir_name + '/' + poster_namewith open(poster_path, "wb")as f:f.write(response.content)return zip(ranking, name, score, number, types, country, language, date, time, other_name, director, screenwriter, performer, m_url, imdb_url)def save_results(data):with open('douban.csv', 'a', encoding="utf-8-sig") as fp:writer = csv.writer(fp)writer.writerow(data)if __name__ == '__main__':num = 0for i in range(0, 250, 25):movie_urls = index_pages(i)for movie_url in movie_urls:results = parse_pages(movie_url)for result in results:num += 1save_results(result)print('第' + str(num) + '条电影信息保存完毕!')time.sleep(3)

【6x00】数据截图

03
04


【7x00】程序不足的地方

程序不足的地方:豆瓣电影有反爬机制,当程序爬取到大约 150 条数据的时候,IP 就会被封掉,第二天 IP 才会解封,可以考虑综合使用多个代理、多个 User-Agent、随机时间暂停等方法进行爬取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437903.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sharepoint学习笔记—ECM系列--3 从.CSV文件导入术语集(Term Sets)

Sharepoint2010支持直接从CSV文件导入术语集(Term Sets)&#xff0c;也就是说你可以先直接在Excel中创建和编辑术语集&#xff0c;然后保存为.CSV文件&#xff0c;再通过Sharepoint2010管理中心提供的管理界面导入术语集到指定的Metadata Service下的指定组中,下面我们来看看如…

使用 hexo-git-backup 插件备份你的 Hexo 博客

2022-01-25 更新&#xff1a;博客新地址&#xff1a;https://www.itbob.cn/&#xff0c;文章距上次编辑时间较远&#xff0c;部分内容可能已经过时&#xff01; 欢迎关注我的专栏&#xff1a;《个人博客搭建&#xff1a;HexoGithub Pages》&#xff0c;从搭建到美化一条龙&…

Sharepoint学习笔记—ECM系列--4 根据位置设置的默认元数据值(Location-Based Metadata Defaults)

如果有这样一个需求&#xff1a;客户在一个SharePoint 2010的站点的document library中创建了不同的文件夹FolderA和FolderB&#xff0c;对于上传到此文件夹的文件记录中有某一个列ColumnM,现在他实现当上传文件到不同的文件夹FolderA或FolderB时&#xff0c;列ColumnM使用不同…

Python3 爬虫实战 — 安居客武汉二手房【requests、Beautiful Soup、CSV】

爬取时间&#xff1a;2019-10-09爬取难度&#xff1a;★★☆☆☆☆请求链接&#xff1a;https://wuhan.anjuke.com/sale/爬取目标&#xff1a;爬取武汉二手房每一条售房信息&#xff0c;包含地理位置、价格、面积等&#xff0c;保存为 CSV 文件涉及知识&#xff1a;请求库 requ…

Sharepoint 修改密码

sharepoint安装在服务器上&#xff0c;比如windows 2008 R2(64), 但是在公司里面经常需要修改电脑的密码&#xff0c;电脑的密码一旦改变则相应的sharepoint服务器场密码也需改变&#xff0c;本文介绍修改sharepoint密码的简单方法&#xff0c;不用在命令行输入命令。 step1:打…

Python3 爬虫实战 — 虎扑论坛步行街【requests、Beautiful Soup、MongoDB】

爬取时间&#xff1a;2019-10-12爬取难度&#xff1a;★★☆☆☆☆请求链接&#xff1a;https://bbs.hupu.com/bxj爬取目标&#xff1a;爬取虎扑论坛步行街的帖子&#xff0c;包含主题&#xff0c;作者&#xff0c;发布时间等&#xff0c;数据保存到 MongoDB 数据库涉及知识&am…

Python3 爬虫实战 — 模拟登陆哔哩哔哩【滑动验证码对抗】

登陆时间&#xff1a;2019-10-21实现难度&#xff1a;★★★☆☆☆请求链接&#xff1a;https://passport.bilibili.com/login实现目标&#xff1a;模拟登陆哔哩哔哩&#xff0c;攻克滑动验证码涉及知识&#xff1a;滑动验证码的攻克、自动化测试工具 Selenium 的使用完整代码&…

Python3 爬虫实战 — 模拟登陆12306【点触验证码对抗】

登陆时间&#xff1a;2019-10-21实现难度&#xff1a;★★★☆☆☆请求链接&#xff1a;https://kyfw.12306.cn/otn/resources/login.html实现目标&#xff1a;模拟登陆中国铁路12306&#xff0c;攻克点触验证码涉及知识&#xff1a;点触验证码的攻克、自动化测试工具 Selenium…

SharePoint无代码工作流设计开发实例——交通费报销流程(一)

开发环境&#xff1a; (1)SharePoint Designer 2010 (2)SharePoint Online(Office 365) 关于Office 365和SharePoint Online的相关信息请参见以下链接 http://blog.csdn.net/miragesky2049/article/details/7242982 1、需求分析 组织结构&#xff1a; 用户类型&#xff1a…

Python3 爬虫实战 — 58同城武汉出租房【加密字体对抗】

爬取时间&#xff1a;2019-10-21爬取难度&#xff1a;★★★☆☆☆请求链接&#xff1a;https://wh.58.com/chuzu/爬取目标&#xff1a;58同城武汉出租房的所有信息涉及知识&#xff1a;网站加密字体的攻克、请求库 requests、解析库 Beautiful Soup、数据库 MySQL 的操作完整代…

SharePoint无代码工作流设计开发实例——交通费报销流程(二)

3、InfoPath表单的设计及发布 (1)数据源和页面设计 域&#xff08;元素&#xff09;和域&#xff08;属性&#xff09;如下&#xff1a; 白色为域&#xff08;元素&#xff09;&#xff0c;该类型的字段&#xff0c;发布时&#xff0c;提升成字段后&#xff0c;列表库的数据是…

SharePoint无代码工作流设计开发实例——交通费报销流程(三)

4、SharePoint Designer无代码工作流的设计 开发工具为SharePoint Designer 2010 新建“列表工作流”&#xff0c;绑定“交通费报销单”表单库 设置工作流启动选项“创建项目时自动启动工作流” 编辑工作流 &#xff08;关于以下工作流详细设计可参考http://blog.csdn.net/mi…

SharePoint学习札记[2] — MOSS2007体系结构概述

熟悉微软Office产品线的人都知道&#xff0c;MOSS 2007的上一个版本SPS 2003的全称是 Office Sharepoint Portal Server&#xff0c;在新版本中&#xff0c;微软去掉了Portal一个词。从这个角度很清楚地看到微软对MOSS 2007的定位&#xff0c;是的&#xff0c;MOSS 已经不再仅仅…

SharePoint学习札记[3] — Office SharePoint Server 2007部署

MOSS的第一步就是部署啦!《0ffice SharePoint Server 2007部署图示指南》图文并茂的展示了OSS2007的部署过程。虽然并不难&#xff0c;但对MOSS还摸不清方向的人来说是个不错的指导。手册的作者没有署名&#xff0c;也查不到出自谁手&#xff0c;在这里对他的劳动成果表示感谢…

SharePoint学习札记[4] — 创建SharePoint站点

为减少创建SharePoint站点过程中的麻烦&#xff0c;先打开IIS管理器&#xff0c;将“默认站点”停止或删除。后面的创建过程中&#xff0c;创建向导会自动创建端口为80的网站。 现在将&#xff1a; 1. 创建两个Web应用程序。 2. 创建共享服务。 3. 创建…

【Python CheckiO 题解】Sun Angle

CheckiO 是面向初学者和高级程序员的编码游戏&#xff0c;使用 Python 和 JavaScript 解决棘手的挑战和有趣的任务&#xff0c;从而提高你的编码技能&#xff0c;本博客主要记录自己用 Python 在闯关时的做题思路和实现代码&#xff0c;同时也学习学习其他大神写的代码。 Chec…

Python CheckiO 题解系列 丨 博客目录索引

CheckiO 是面向初学者和高级程序员的编码游戏&#xff0c;使用 Python 和 JavaScript 解决棘手的挑战和有趣的任务&#xff0c;从而提高你的编码技能&#xff0c;本题解系列主要记录自己在用 Python 闯关时的做题思路和实现代码&#xff0c;同时也学习学习其他大神写的代码。 …

文带你深入了解 Redis 内存模型

前言 Redis是目前最火爆的内存数据库之一&#xff0c;通过在内存中读写数据&#xff0c;大大提高了读写速度&#xff0c;可以说Redis是实现网站高并发不可或缺的一部分。 我们使用Redis时&#xff0c;会接触Redis的5种对象类型&#xff08;字符串、哈希、列表、集合、有序集合…

【Python CheckiO 题解】Pawn Brotherhood

CheckiO 是面向初学者和高级程序员的编码游戏&#xff0c;使用 Python 和 JavaScript 解决棘手的挑战和有趣的任务&#xff0c;从而提高你的编码技能&#xff0c;本博客主要记录自己用 Python 在闯关时的做题思路和实现代码&#xff0c;同时也学习学习其他大神写的代码。 Chec…

【Python CheckiO 题解】Xs and Os Referee

CheckiO 是面向初学者和高级程序员的编码游戏&#xff0c;使用 Python 和 JavaScript 解决棘手的挑战和有趣的任务&#xff0c;从而提高你的编码技能&#xff0c;本博客主要记录自己用 Python 在闯关时的做题思路和实现代码&#xff0c;同时也学习学习其他大神写的代码。 Chec…