Python爬虫之豆瓣排行榜(正则表达式)
1. 项目目标
使用Chrome浏览器打开网页/ ,切换到【榜单】,【TOP100榜】。本次项目就是要获取豆瓣排名Top100的电影排名、电影名称、主演,以及豆瓣评分。
2.实施
2.1 网页分析
网页翻到最后,点击“下一页”,发现网址变成了“/board/4?offset=10”;再点击下一页,网址又变成“/board/4?offset=20”;
由此推测,任意页网址是“/board/4?offset=x”,其中x的值是页数的10倍(每页显示10部电影)。
2.2 请求网页
打开第一页,键盘按F12打开【开发者工具】,再按一次F5刷新页面,依次点击“Network"、“4?offset=0”(即name列表第一个)、“Headers”;
在“Request Headers”中可以找到浏览器的请求头信息,包括cookie、host、User-Agent等。
import requestsurl="/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 reresult=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)更多正则表达式的用法请参考博客:
/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 pdpd.DataFrame({'index':index,'title':title,'star':star,'score':score})
结果如下图:
到这里,就实现了单页数据的爬取,接下来通过遍历各页的url,实现TOP100的全部信息爬取:
for page in range(10):url='/board/4?offset=%d'%(10*page)......
2.4 本案例完整代码如下:
import reimport pandas as pdimport requestsimport osimport timestart =time.clock()index,title,star,score=[],[],[],[]def get_one_page(page):url='/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.textdef 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})