目录
1、项目背景2、导入相关库3、逐个提取字段1)请求页面2)观察代码中的中文是否正常显示3)通过Beautiful Soup解析代码内容4)提取字段啦先来提取短评内容吧用同样的方法完成用户名、用户主页、有用数、评论时间、用户头像的提取4、提取的数据导入DataFrame5、分块代码打包成一个函数6、爬取不同页数的短评7、同时爬取n页短评1)观察网页规律2)用循环语句爬取不同页短评8、爬取豆瓣电影任一电影的短评1、项目背景
最近关注了一个比较有干货的数据分析类的公众号,经常会推一些有趣又贴近现实的数据分析相关案例和文章,其中有一篇是关于粽子销量的爬取的案例,我觉得挺有意思的。心里在想,为啥我有资源不自己学会爬虫呢?这样的话,自己想了解点什么就可以自己去网上爬取相关讯息了,简直太香了。于是乎,拾起晾在一旁的学习资源,学了起来。第一个小案例,就是爬取豆瓣电影中的《寄生虫》的短评(阉割版)。想学的小伙伴们,一起撸起袖子加油干吧!!
2、导入相关库
操作环境:anaconda中的Jupyter
import requests #导入调用网址的库from bs4 import BeautifulSoup #导入解析库,一般用lxmlimport numpy as np #这个不用说大家都知道啦import pandas as pd #这个不用说大家都知道啦2
3、逐个提取字段
1)请求页面
url="/subject/27010768/comments?status=P" #通过百度搜索网页复制的豆瓣电影《寄生虫》短评的第一页的网址headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'} #模拟浏览器r=requests.get(url,headers=headers) #打开url网页,返回一个结果(代码)r
如果输出的结果是<Response [200]>,代表可以正常打开网页获取代码。如果返回的不是200,则可能是代码有误,或者网页本身是打不开的等等。
2)观察代码中的中文是否正常显示
r.text
如果输出结果代码中的中文没有正常显示,需要加一个修改代码格式的语句:
r.encoding=r.apparent_encoding
如果还是不能正常显示,可以用以下方法100%解决:使用手动观察r.text查看content后面的“”,然后输入代码:
r.encoding="IE=edge,chrome=1" #此处假设text里面的content后面的引号中内容是“IE=edge,chrome=1”
3)通过Beautiful Soup解析代码内容
如何在这个字符串中高效搜索出我们需要的内容?用Beautiful Soup,将字符串转为BeautifulSoup格式。
bs=BeautifulSoup(r.text,"lxml") #“lxml”是Beautiful Soup的常用解析器
4)提取字段啦
先来提取短评内容吧
第一步:需要通过查看短评内容对应的代码块寻找搜索关键字,方法:打开网页,右键,选择“审查元素”——鼠标选中短评内容,查看代码块关键字有哪些?
通过观察发现搜索的关键字有span和short。接下来通过find/find_all来定位和提取出短评内容。其中find只查找定位出的第一个内容,find_all定位全部内容。这里,我们需要定位出全部内容。
bs.find_all("span","short")
第二步:定义一个列表,把定位到的内容放到列表中去:
short=[]for i in bs.find_all("span","short"):short.append(i.text)short
备注:上述两步,可以通过列表生成式简写,让代码变得简洁:
short=[i.text for i in bs.find_all("span","short")]
用同样的方法完成用户名、用户主页、有用数、评论时间、用户头像的提取
1.提取用户名:
username=[i.find("a").text for i in bs.find_all("span","comment-info")]
2.提取用户主页:即上图中的href后面的链接
homepage=[i.find("a")["href"] for i in bs.find_all("span","comment-info")]
3.提取有用数:
votes=[i.text for i in bs.find_all("span","votes")]
4.提取评论时间:
comment_time=[i.text for i in bs.find_all("span","comment-time")]
发现输出的结果中时间的左右两边存在很多空格,需要加一个.strip()去除空格:
comment_time=[i.text.strip() for i in bs.find_all("span","comment-time")] #.strip()去除空格
5.提取用户头像:
img=[i.find("img")["src"] for i in bs.find_all("div","avatar")]
4、提取的数据导入DataFrame
目的当然是为了好看和便于导出分析啦
第一步:创建一个空DataFrame
df=pd.DataFrame()
第二步:依次将上面的数据传入进去
df["用户名"]=usernamedf["评论时间"]=comment_timedf["评论内容"]=shortdf["有用人数"]=votesdf["用户主页"]=homepagedf["用户头像"]=imgdf
5、分块代码打包成一个函数
Tips:
1.如何同时选中连续的多行代码?选中第一行代码,按住Ctrl,选中最后一行代码;
2.如何复制粘贴多行代码?Juyter上方工具栏有个书本样的复制,旁边有个粘贴;
3.如何快速合并选中的多行代码?通过快捷键shift+M;
4.如何快速将选中的代码整体往右缩进?按Tap键。
因代码行较多,可通过上述Tips1-3快速复制代码并将复制的代码合并。合并后进行整理和删除多余代码行,最终打包成的函数如下:
def get_oen_page_short(url):"""函数功能:传入一个豆瓣短评的页面的网址,返回这个页面的dataframe格式的数据。参数:url """headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'}r=requests.get(url,headers=headers)bs=BeautifulSoup(r.text,"lxml")bs.find_all("span","short")#列表生成式提取短评short=[i.text for i in bs.find_all("span","short")]#列表生产式提取用户名username=[i.find("a").text for i in bs.find_all("span","comment-info")]#提取用户主页homepage=[i.find("a")["href"] for i in bs.find_all("span","comment-info")]#提取时间comment_time=[i.text.strip() for i in bs.find_all("span","comment-time")] #添加.strip()#提取用户的头像img=[i.find("img")["src"] for i in bs.find_all("div","avatar")]#提取评论有用数votes=[i.text for i in bs.find_all("span","votes")]#将提取的上述数据导入DataFrame。需要先导入DataFrame包:创建一个空的DataFrame,依次将上面的数据传入进去#第一步:df=pd.DataFrame()#第二步:df["用户名"]=usernamedf["评论时间"]=comment_timedf["评论内容"]=shortdf["有用人数"]=votesdf["用户主页"]=homepagedf["用户头像"]=imgreturn df
6、爬取不同页数的短评
举例:爬取第三页的短评:url:/subject/27010768/comments?start=40&limit=20&sort=new_score&status=P
将url赋值到上述打包好的函数中。
get_oen_page_short("/subject/27010768/comments?start=40&limit=20&sort=new_score&status=P")
爬取出的结果如下:
成功!整理到12:04分,可以安心去吃饭了,嘿嘿嘿。如果此文对你有用,给点个赞呗,么么哒~
抽空把连续爬取N页和任意爬取豆瓣电影中的任意一部电影的短评这两项工作完成,这个爬虫案例就算完整啦~
7、同时爬取n页短评
1)观察网页规律
首先需要观察一下不同页的短评的网址有什么规律?只有start后面的数字有变化,分别是0/20/40
第一页:/subject/27010768/comments?start=0&limit=20&s
ort=new_score&status=P
第二页:/subject/27010768/comments?start=20&limit=20&sort=new_score&status=P
第三页:/subject/27010768/comments?start=40&limit=20&sort=new_score&status=P
2)用循环语句爬取不同页短评
用一个for循环,爬取各页的数据并放入DataFrame中,然后进行合并(append-纵向拼接;concat-横向或纵向拼接):
df_all=pd.DataFrame() #新建一个空的DataFrame进行合并for i in range(10)url_test=”/subject/27010768/comments?start={}&limit=20&sort=new_score&status=P”.format(i*20)df=get_oen_page_short(url_test)#将提取出来的DataFrame合并进去df_all=df_all.append(df,ignore_index=True)
注意:
1.df_all如果不重新定义会没有数据,只是一个副本没有覆盖掉df_all。
2.发现索引有问题,需要加个忽略原来的索引ignore_index=True。
8、爬取豆瓣电影任一电影的短评
要先观察不同电影的区别,发现只有subject后面的数字不同。
霸王别姬:/subject/1291546/comments?status=P
泰坦尼克号:/subject/1292722/comments?status=P
def get_douban_movie_short(movie_id,page_num):"""功能:传入电影ID和页数就可以获取对应的数据,返回:DataFrame形式的短评数据"""#我们需要每次巡检得到的DataFrame进行合并#先建一个空的DataFrame用于合并df_all=pd.DataFrame() #新建一个空的DataFrame进行合并for i in range(page_num):url_test="/subject/{}/comments?start={}&limit=20&sort=new_score&status=P".format(movie_id,i*20) #subject后面的数字用{}代表电影IDdf=get_oen_page_short(url_test)#将提取出来的DataFrame合并进去df_all=df_all.append(df,ignore_index=True) return df_all
1.爬取霸王别姬6页短评
bawang=get_douban_movie_short(1291546,6)bawang
输出结果如下:
2.爬取泰坦尼克号6页短评
titanic=get_douban_movie_short(1292722,6)titanic
将以上数据保存到本地:
jishengchong.to_excel("寄生虫评论_汇总.xlsx")