Python爬虫之豆瓣排行榜(正则表达式)
1. 项目目标
使用Chrome浏览器打开网页https://maoyan.com/ ,切换到【榜单】,【TOP100榜】。本次项目就是要获取豆瓣排名Top100的电影排名、电影名称、主演,以及豆瓣评分。
2.实施
2.1 网页分析
网页翻到最后,点击“下一页”,发现网址变成了“https://maoyan.com/board/4?offset=10”;再点击下一页,网址又变成“https://maoyan.com/board/4?offset=20”;
由此推测,任意页网址是“https://maoyan.com/board/4?offset=x”,其中x的值是页数的10倍(每页显示10部电影)。
2.2 请求网页
打开第一页,键盘按F12打开【开发者工具】,再按一次F5刷新页面,依次点击“Network"、“4?offset=0”(即name列表第一个)、“Headers”;
在“Request Headers”中可以找到浏览器的请求头信息,包括cookie、host、User-Agent等。
import requests
url="https://maoyan.com/board/4?offset=0"
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
r=requests.get(url,headers=headers)
查看网页源代码
r.text
可以看到,每一部电影的信息都在"dd"这个标签中,注意评分的整数部分和小数部分是分开的。
2.3解析网页
此处使用正则表达式解析:
import re
result=re.findall('<i\sclass="board-index board-index-(.*?)".*?title="(.*?)".*?主演:(.*?)\\n.*?上映时间:.*?<.*?integer">(.*?)<.*?fraction">(.*?)<.*?/i>',r.text,re.S)
说明:
1)【.*?】的组合前后加上特定上下文,堪称无敌匹配,我很喜欢这么用;比如在"…1203" title=“霸王别姬” data…“找到"霸王别姬"四个子,上文是【title=”】,下文是【" data】,在上下文中间加入这个组合,就可以完美匹配出中间的内容;
2)当需要提取一串字符的多项内容时,每一项内容用括号括起来,用findall输出结果;
3)最后面re.S表示可以跨行匹配,原字符串多行显示时需要这么用;
4)更多正则表达式的用法请参考博客:
https://blog.csdn.net/bingocoder/article/details/103746826
result
得到是结果是列表类型,列表中的每个元素是tuple类型,此处通过遍历列表提取信息:
index,title,star,score=[],[],[],[]
for i in result:
index.append(i[0]) #获取每个元组中的第一个元素,即序号
title.append(i[1])
star.append(i[2])
score.append(i[3]+str(i[4])) #得分为整数部分+小数部分
score
将所有数据信息整理成DataFrame:
import pandas as pd
pd.DataFrame({'index':index,'title':title,'star':star,'score':score})
结果如下图:
到这里,就实现了单页数据的爬取,接下来通过遍历各页的url,实现TOP100的全部信息爬取:
for page in range(10):
url='https://maoyan.com/board/4?offset=%d'%(10*page)
...
...
2.4 本案例完整代码如下:
import re
import pandas as pd
import requests
import os
import time
start =time.clock()
index,title,star,score=[],[],[],[]
def get_one_page(page):
url='https://maoyan.com/board/4?offset=%d'%(10*page)
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
r=requests.get(url,headers=headers)
if r.status_code==200:
return r.text
def jiexi(html):
result=re.findall('<i\sclass="board-index board-index-(.*?)".*?title="(.*?)".*?主演:(.*?)\\n.*?上映时间:.*?<.*?integer">(.*?)<.*?fraction">(.*?)<.*?/i>',html,re.S)
for i in result:
index.append(i[0])
title.append(i[1])
star.append(i[2])
score.append(i[3]+str(i[4]))
for i in range(10):
jiexi(get_one_page(i))
time.sleep(1)
pd.DataFrame({'index':index,'title':title,'star':star,'score':score})