一起学爬虫——通过爬取豆瓣电影top250学习requests库的使用
学习一门技术最快的方式是做项目,在做项目的过程中对相关的技术查漏补缺。
本文通过爬取豆瓣top250电影学习python requests的使用。
1、准备工作
在pycharm中安装request库
请看上图,在pycharm中依次点击:File->Settings。然后会弹出下图的界面:
点击2中左上角的“+”按钮,弹出下图的界面:
在右上角的查询框输入requests,然后点击“Install Package”按钮安装requests插件。
2、目标
抓取每部电影的名字、主演、评分、图片等信息, 并保存在txt文本文件中。
3、分析豆瓣top250电影首页
1、分析豆瓣电影top250的网页https://movie.douban.com/top250,在浏览器中打开该网页:
可以看到一页显示25部电影。250部电影分10显示:
要抓取250部电影需要抓取10次。下面是每一页的网页链接:
https://movie.douban.com/top250?start=0&filter= 首页,等效于https://movie.douban.com/top250
https://movie.douban.com/top250?start=25&filter= #第2页
https://movie.douban.com/top250?start=50&filter= #第3页
...
...
...
https://movie.douban.com/top250?start=225&filter= #第10页
通过分析上面的链接可以得出一个规律:start=0显示1到25部电影,start=25显示26到50部电影,以此类推,在抓取每一页的电影时,是需要改变start的值即可。
4、抓取豆瓣电影top250首页
代码如下:
import requests
import re
import json
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
url = \'https://movie.douban.com/top250?start=0&filter=\'
proxies = {
"http": "http://123.207.96.189:80"
}
response = requests.get(url, proxies = proxies,headers=headers)
text = response.text
print(text)
通过上述的代码我们可以学习到requests类库中如何使用headers信息和设置代理。
headers头信息和proxies代理信息都是定义为dict词典变量,然后在调用requests.get()方法时传输这个两个参数:
response = requests.get(url, proxies = proxies,headers=headers)
很多网站都有反爬虫的措施,对于没有headers头信息的请求一律认为是爬虫,禁止该请求的访问。因此在每次爬取网页时都需要加上headers头信息。
对于访问过于频繁的请求,客户端的IP会被禁止访问,因此设置代理可以将请求伪装成来自不同的IP,前提是要保证代理的IP地址是有效的。
5、抓取每一部电影的信息
查看网页源代码有两种方式:
通过鼠标右键点击查看“查看源文件”选项,或者通过浏览器的开发者工具选项,然后点击Network查看源码:
下图是一部电影在HTML网页中的显示,我们要做的就是从HTML中提取出电影名称、主演、图片等信息。
提取电影的信息需要用到正则表达式。
通过上图可以看到一部电影的信息对应的源代码是<div class="item">
节点,红色框所示。我们先用正则表达式提取到每部电影的所有信息:regix = \'<div class="item">\'
class为pic的div节点包含电影的排名和电影图片信息,提取电影排名和电影图片信息的正则表:
regix = \'<div class="item">.*?<div class="pic">.*?<em class="">(.*?)</em>.*?<img.*?src="(.*?)" class="">\'
class为info的div标签中包含了电影的名字、导演和演员等信息,电影名字是在class为hd的div的节点内,<span class="title">
节点内包含的是电影的名字,<span class="other">
节点内包含的是电影的别名,上图中的褐色框部分,因此提取电影名字的正则表达式为:
regix = \'<div class="item">.*?<div class="pic">.*?<em class="">(.*?)</em>.*?<img.*?src="(.*?)" class="">.*?div
class="info.*?class="hd".*?class="title">(.*?)</span>.*?class="other">(.*?)</span>\'
class为bd的节点内包含的是电影的导演和主演信息,其中class为“”的p节点内包含的是电影的导演和演员信息,其中还包含了<br>
标签,上图中的紫色框部分,为了提取电影导演和演员的信息,正则表达式改写为:
regix = \'<div class="item">.*?<div class="pic">.*?<em class="">(.*?)</em>.*?<img.*?src="(.*?)" class="">.*?div
class="info.*?class="hd".*?class="title">(.*?)</span>.*?class="other">(.*?)</span>.*?<div class="bd">.*?<p class="">(.*?)<br>(.*?)</p>\'
class为start的div标签中包含的是电影的星级和评分,上图黑色框部分。提取星级和评分的规则和提取电影排名、图片等信息类似,最后提取整个电影信息的正则表达式为:
regix = \'<div class="item">.*?<div class="pic">.*?<em class="">(.*?)</em>.*?<img.*?src="(.*?)" class="">.*?div class="info.*?class="hd".*?class="title">(.*?)</span>.*?class="other">(.*?)</span>.*?<div class="bd">.*?<p class="">(.*?)<br>(.*?)</p>.*?class="star.*?<span class="(.*?)"></span>.*?span class="rating_num".*?average">(.*?)</span>\'
提取一页中所有电影信息的代码如下:
import requests
import re
import json
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
url = \'https://movie.douban.com/top250?start=0&filter=\'
proxies = {
"http": "http://123.207.96.189:80"
}
response = requests.get(url, proxies = proxies,headers=headers)
text = response.text
regix = \'<div class="item">.*?<div class="pic">.*?<em class="">(.*?)</em>.*?<img.*?src="(.*?)" class="">.*?div class="info.*?class="hd".*?class="title">(.*?)</span>.*?class="other">(.*?)</span>.*?<div class="bd">.*?<p class="">(.*?)<br>(.*?)</p>.*?class="star.*?<span class="(.*?)"></span>.*?span class="rating_num".*?average">(.*?)</span>\'
results = re.findall(regix,text,re.S)
for item in results:
print(item)
结果为:
(\'1\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg\', \'肖申克的救赎\', \' / 月黑高飞(港) / 刺激1995(台)\', \'\n 导演: 弗兰克·德拉邦特 Frank Darabont 主演: 蒂姆·罗宾斯 Tim Robbins /...\', \'\n 1994 / 美国 / 犯罪 剧情\n \', \'rating5-t\', \'9.6\')
(\'2\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1910813120.jpg\', \'霸王别姬\', \' / 再见,我的妾 / Farewell My Concubine\', \'\n 导演: 陈凯歌 Kaige Chen 主演: 张国荣 Leslie Cheung / 张丰毅 Fengyi Zha...\', \'\n 1993 / 中国大陆 香港 / 剧情 爱情 同性\n \', \'rating5-t\', \'9.6\')
(\'3\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p511118051.jpg\', \'这个杀手不太冷\', \' / 杀手莱昂 / 终极追杀令(台)\', \'\n 导演: 吕克·贝松 Luc Besson 主演: 让·雷诺 Jean Reno / 娜塔莉·波特曼 ...\', \'\n 1994 / 法国 / 剧情 动作 犯罪\n \', \'rating45-t\', \'9.4\')
(\'4\', \'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p510876377.jpg\', \'阿甘正传\', \' / 福雷斯特·冈普\', \'\n 导演: Robert Zemeckis 主演: Tom Hanks / Robin Wright Penn / Gary Sinise\', \'\n 1994 / 美国 / 剧情 爱情\n \', \'rating45-t\', \'9.4\')
(\'5\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p510861873.jpg\', \'美丽人生\', \' / 一个快乐的传说(港) / Life Is Beautiful\', \'\n 导演: 罗伯托·贝尼尼 Roberto Benigni 主演: 罗伯托·贝尼尼 Roberto Beni...\', \'\n 1997 / 意大利 / 剧情 喜剧 爱情 战争\n \', \'rating5-t\', \'9.5\')
(\'6\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p457760035.jpg\', \'泰坦尼克号\', \' / 铁达尼号(港 / 台)\', \'\n 导演: 詹姆斯·卡梅隆 James Cameron 主演: 莱昂纳多·迪卡普里奥 Leonardo...\', \'\n 1997 / 美国 / 剧情 爱情 灾难\n \', \'rating45-t\', \'9.3\')
(\'7\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1606727862.jpg\', \'千与千寻\', \' / 神隐少女(台) / Spirited Away\', \'\n 导演: 宫崎骏 Hayao Miyazaki 主演: 柊瑠美 Rumi Hîragi / 入野自由 Miy...\', \'\n 2001 / 日本 / 剧情 动画 奇幻\n \', \'rating45-t\', \'9.3\')
(\'8\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p492406163.jpg\', \'辛德勒的名单\', \' / 舒特拉的名单(港) / 辛德勒名单\', \'\n 导演: 史蒂文·斯皮尔伯格 Steven Spielberg 主演: 连姆·尼森 Liam Neeson...\', \'\n 1993 / 美国 / 剧情 历史 战争\n \', \'rating5-t\', \'9.5\')
(\'9\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p513344864.jpg\', \'盗梦空间\', \' / 潜行凶间(港) / 全面启动(台)\', \'\n 导演: 克里斯托弗·诺兰 Christopher Nolan 主演: 莱昂纳多·迪卡普里奥 Le...\', \'\n 2010 / 美国 英国 / 剧情 科幻 悬疑 冒险\n \', \'rating45-t\', \'9.3\')
(\'10\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1461851991.jpg\', \'机器人总动员\', \' / 瓦力(台) / 太空奇兵·威E(港)\', \'\n 导演: 安德鲁·斯坦顿 Andrew Stanton 主演: 本·贝尔特 Ben Burtt / 艾丽...\', \'\n 2008 / 美国 / 爱情 科幻 动画 冒险\n \', \'rating45-t\', \'9.3\')
(\'11\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p524964016.jpg\', \'忠犬八公的故事\', \' / 忠犬小八(台) / 秋田犬八千(港)\', \'\n 导演: 莱塞·霍尔斯道姆 Lasse Hallström 主演: 理查·基尔 Richard Ger...\', \'\n 2009 / 美国 英国 / 剧情\n \', \'rating45-t\', \'9.3\')
(\'12\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p579729551.jpg\', \'三傻大闹宝莱坞\', \' / 三个傻瓜(台) / 作死不离3兄弟(港)\', \'\n 导演: 拉库马·希拉尼 Rajkumar Hirani 主演: 阿米尔·汗 Aamir Khan / 卡...\', \'\n 2009 / 印度 / 剧情 喜剧 爱情 歌舞\n \', \'rating45-t\', \'9.2\')
(\'13\', \'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p511146807.jpg\', \'海上钢琴师\', \' / 声光伴我飞(港) / 一九零零的传奇\', \'\n 导演: 朱塞佩·托纳多雷 Giuseppe Tornatore 主演: 蒂姆·罗斯 Tim Roth / ...\', \'\n 1998 / 意大利 / 剧情 音乐\n \', \'rating45-t\', \'9.2\')
(\'14\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1910824951.jpg\', \'放牛班的春天\', \' / 歌声伴我心(港) / 唱诗班男孩\', \'\n 导演: 克里斯托夫·巴拉蒂 Christophe Barratier 主演: 杰拉尔·朱诺 Géra...\', \'\n 2004 / 法国 瑞士 德国 / 剧情 音乐\n \', \'rating45-t\', \'9.2\')
(\'15\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2455050536.jpg\', \'大话西游之大圣娶亲\', \' / 西游记完结篇仙履奇缘 / 齐天大圣西游记\', \'\n 导演: 刘镇伟 Jeffrey Lau 主演: 周星驰 Stephen Chow / 吴孟达 Man Tat Ng...\', \'\n 1995 / 香港 中国大陆 / 喜剧 爱情 奇幻 冒险\n \', \'rating45-t\', \'9.2\')
(\'16\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p479682972.jpg\', \'楚门的世界\', \' / 真人Show(港) / 真人戏\', \'\n 导演: 彼得·威尔 Peter Weir 主演: 金·凯瑞 Jim Carrey / 劳拉·琳妮 Lau...\', \'\n 1998 / 美国 / 剧情 科幻\n \', \'rating45-t\', \'9.2\')
(\'17\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2190556185.jpg\', \'教父\', \' / Mario Puzo's The Godfather\', \'\n 导演: 弗朗西斯·福特·科波拉 Francis Ford Coppola 主演: 马龙·白兰度 M...\', \'\n 1972 / 美国 / 剧情 犯罪\n \', \'rating45-t\', \'9.2\')
(\'18\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2539252713.jpg\', \'龙猫\', \' / 邻居托托罗 / 邻家的豆豆龙\', \'\n 导演: 宫崎骏 Hayao Miyazaki 主演: 日高法子 Noriko Hidaka / 坂本千夏 Ch...\', \'\n 1988 / 日本 / 动画 奇幻 冒险\n \', \'rating45-t\', \'9.1\')
(\'19\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2206088801.jpg\', \'星际穿越\', \' / 星际启示录(港) / 星际效应(台)\', \'\n 导演: 克里斯托弗·诺兰 Christopher Nolan 主演: 马修·麦康纳 Matthew Mc...\', \'\n 2014 / 美国 英国 加拿大 冰岛 / 剧情 科幻 冒险\n \', \'rating45-t\', \'9.2\')
(\'20\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1363250216.jpg\', \'熔炉\', \' / 无声呐喊(港) / 漩涡\', \'\n 导演: 黄东赫 Dong-hyuk Hwang 主演: 孔侑 Yoo Gong / 郑有美 Yu-mi Jeong ...\', \'\n 2011 / 韩国 / 剧情\n \', \'rating45-t\', \'9.2\')
(\'21\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2233971046.jpg\', \'无间道\', \' / Infernal Affairs / Mou gaan dou\', \'\n 导演: 刘伟强 / 麦兆辉 主演: 刘德华 / 梁朝伟 / 黄秋生\', \'\n 2002 / 香港 / 剧情 犯罪 悬疑\n \', \'rating45-t\', \'9.1\')
(\'22\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1312700744.jpg\', \'当幸福来敲门\', \' / 寻找快乐的故事(港) / 追求快乐\', \'\n 导演: 加布里尔·穆奇诺 Gabriele Muccino 主演: 威尔·史密斯 Will Smith ...\', \'\n 2006 / 美国 / 剧情 传记 家庭\n \', \'rating45-t\', \'9.0\')
(\'23\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1454261925.jpg\', \'触不可及\', \' / 闪亮人生(港) / 逆转人生(台)\', \'\n 导演: 奥利维·那卡什 Olivier Nakache / 艾力克·托兰达 Eric Toledano 主...\', \'\n 2011 / 法国 / 剧情 喜剧\n \', \'rating45-t\', \'9.2\')
(\'24\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p663036666.jpg\', \'怦然心动\', \' / 萌动青春 / 青春萌动\', \'\n 导演: 罗伯·莱纳 Rob Reiner 主演: 玛德琳·卡罗尔 Madeline Carroll / 卡...\', \'\n 2010 / 美国 / 剧情 喜剧 爱情\n \', \'rating45-t\', \'9.0\')
(\'25\', \'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1963126880.jpg\', \'乱世佳人\', \' / 飘\', \'\n 导演: 维克多·弗莱明 Victor Fleming / 乔治·库克 George Cukor 主演: 费...\', \'\n 1939 / 美国 / 剧情 历史 爱情 战争\n \', \'rating45-t\', \'9.2\')
从上面的结果看到电影的星级是rating5-t、rating45-t、rating4-t这样的字符代表五星、四星半、四星等。转换代码为:
def star_transfor(str):
if str == \'rating5-t\':
return \'五星\'
elif str == \'rating45-t\' :
return \'四星半\'
elif str == \'rating4-t\':
return \'四星\'
elif str == \'rating35-t\' :
return \'三星半\'
elif str == \'rating3-t\':
return \'三星\'
elif str == \'rating25-t\':
return \'两星半\'
elif str == \'rating2-t\':
return \'两星\'
elif str == \'rating15-t\':
return \'一星半\'
elif str == \'rating1-t\':
return \'一星\'
else:
return \'无星\'
在爬取网页时,会将图片也爬取下来,下面的代码是将每部电影的图片保存到本地:
def down_image(url,headers):
r = requests.get(url,headers = headers)
filename = re.search(\'/public/(.*?)$\',url,re.S).group(1)
with open(filename,\'wb\') as f:
f.write(r.content)
爬取到网页的信息后,一般会将爬取的信息保存到数据库或文本文件中,下面的代码是将爬取到的电影信息保存到文本文件中:
def write_movies_file(str):
with open(\'douban_film.txt\',\'a\',encoding=\'utf-8\') as f:
f.write(json.dumps(str,ensure_ascii=False) + \'\n\')
写入文本文件用到了json库的dumps方法,该方法实现了字典的序列化,并且要指定ensure_ascii参数为False,保证中文不乱码。
write_movies_file方法传入的是一个字典的参数,因此在爬取到一部电影的信息时,需要将电影信息格式化为一个字典,代码为:
results = re.findall(regix, text, re.S)
for item in results:
yield {
\'电影名称\' : item[2] + \' \' + re.sub(\' \',\'\',item[3]),
\'导演和演员\' : re.sub(\' \',\'\',item[4].strip()),
\'评分\': star_transfor(item[6].strip()) + \'/\' + item[7] + \'分\',
\'排名\' : item[0]
}
到目前为止,我们已经实现了爬取一页电影的信息,一页包含有25部电影,250部电影有10页,之前已经提到过,改变start的值即可抓取不同页的电影,下面的代码是构造10页电影url的代码:
for offset in range(0, 250, 25):
url = \'https://movie.douban.com/top250?start=\' + str(offset) +\'&filter=\'
爬取豆瓣电影top250的完整代码如下:
import requests
import re
import json
def parse_html(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url, headers=headers)
text = response.text
regix = \'<div class="pic">.*?<em class="">(.*?)</em>.*?<img.*?src="(.*?)" class="">.*?div class="info.*?class="hd".*?class="title">(.*?)</span>.*?class="other">\' \
\'(.*?)</span>.*?<div class="bd">.*?<p class="">(.*?)<br>(.*?)</p>.*?class="star.*?<span class="(.*?)"></span>.*?\' \
\'span class="rating_num".*?average">(.*?)</span>\'
results = re.findall(regix, text, re.S)
for item in results:
down_image(item[1],headers = headers)
yield {
\'电影名称\' : item[2] + \' \' + re.sub(\' \',\'\',item[3]),
\'导演和演员\' : re.sub(\' \',\'\',item[4].strip()),
\'评分\': star_transfor(item[6].strip()) + \'/\' + item[7] + \'分\',
\'排名\' : item[0]
}
def main():
for offset in range(0, 250, 25):
url = \'https://movie.douban.com/top250?start=\' + str(offset) +\'&filter=\'
for item in parse_html(url):
print(item)
write_movies_file(item)
def write_movies_file(str):
with open(\'douban_film.txt\',\'a\',encoding=\'utf-8\') as f:
f.write(json.dumps(str,ensure_ascii=False) + \'\n\')
def down_image(url,headers):
r = requests.get(url,headers = headers)
filename = re.search(\'/public/(.*?)$\',url,re.S).group(1)
with open(filename,\'wb\') as f:
f.write(r.content)
def star_transfor(str):
if str == \'rating5-t\':
return \'五星\'
elif str == \'rating45-t\' :
return \'四星半\'
elif str == \'rating4-t\':
return \'四星\'
elif str == \'rating35-t\' :
return \'三星半\'
elif str == \'rating3-t\':
return \'三星\'
elif str == \'rating25-t\':
return \'两星半\'
elif str == \'rating2-t\':
return \'两星\'
elif str == \'rating15-t\':
return \'一星半\'
elif str == \'rating1-t\':
return \'一星\'
else:
return \'无星\'
if __name__ == \'__main__\':
main()
总结
使用requests爬取一个网页的基本步骤:
- 设置头信息。
- 设置代理
- 使用get方法爬取网页
- 使用正则表达式提取相应的信息
- 下载图片
- 将爬取到的数据保存到文本文件或数据库中。
通过本文可以学习到如何使用requests库爬取网页,使用正则表达式提取网页的信息,下载图片,保存信息到文本文件中。