第一次爬虫就是爬微博的评论(爬虫—只要能看就能爬)
准备工作:
Python2.7(看个人习惯)、FireFox浏览器(看个人习惯)
Python安装什么的网上一大堆教程,我不班门弄斧了
FireFox感觉我个人感觉好用一点,比起全英版的Chrome
from selenium import webdriver#这是重中之重咯,现在微博的评论都是有动态加载的,我是靠这个去控制鼠标行为的
import time#休眠(效果你懂的)、记录当前时间
import xlwt#写入文件用的
上面那几句只是记录一下需要用到的包
url = '******'#自己随便找个微博链接试试吧,不过如果你配置不够,不建议你找5w以上的,超级卡,这些还是得看配置的,网页需缓存
driver = webdriver.Firefox()#打开浏览器
driver.get(url)#输入链接并加载
time.sleep(10)#休眠一下,我不是机器人
此时此刻,如果你把网络断了,然后拉到页面最底下,会发现,评论显示是不全的,然后还有一个“正在加载”的东东显示,而且这个玩意如果你不拉下去是不会帮你加载的,如果你直接爬,你只能爬前面几十条。
重新联网,你会看到又加载N条评论出来,这时候我们就弄一个js,控制鼠标帮我们把页面拉到最底下,使得最大限量的评论显示出来
js="var q=document.documentElement.scrollTop=100000"#10w是指拉到位置值为10w的地方,当然,一般来说,刚加载的网页不会那么长,不然缓存都直接使电脑奔溃
for i in range(10):#重复个10次(当然可以设置更多,但其实一般1-2次就OK了),防止页面没加载完
driver.execute_script(js)#调用js,将页面拖到底
time.sleep(2)
你以为这样评论就显示全了?
其实还没,你看看是不是有一个“查看更多”按钮,点一下,好像多了几十条,但是还有这个按钮,那就是代表还有更多评论没显示,爬虫的中心是什么,能看的就能爬,你都还没看到,那就是还不能爬了,所以,继续点吧。
手点好像有点慢,有点累,那就换程序控制点击吧
接下来就是通过定位“查看更多”这个按钮来使全部的评论都显示出来
Selenium库中定位的方式有很多种(诸如什么id定位、name定位、class定位等等,我这篇爬虫用了其中几个,各有各的好处,但还是要亲自试试吧)
PS:原本想转载一篇关于Selenium中的定位方式,但是不知道会不会侵权什么的,就自己去百度吧,我最多在文章末尾介绍一下我用到的几个定位方式
#查看更多直至全部显示
for i in range(20):
while (1):#只要循环体能运行就一直循环(因为不知道需要点击多少次“查看更多”,所以会使用while(true)循环
try:#尝试,若报错,执行except体
driver.find_element_by_class_name("more_txt").click()#通过class name定位,重复点解“查看更多”
time.sleep(0.8)#休眠
except:
break#结束循环
time.sleep(2)
既然已经全部都显示了,那就开始爬吧,每一条评论呢我们能看见的基本都是评论用户昵称、评论内容、评论时间、评论的回复人数,评论的点赞数(我个人是觉得这2个没什么必要),然后看不见的就是评论用户的链接、评论用户的ID。
###如果想要进阶的话可以爬更深层次的评论用户的信息(地址、性别、微博等级、关注数、粉丝数、微博量、生日、个人简介等等),不过这个就看个人需要了。
我这里就只爬了评论用户昵称、评论用户的链接、评论用户的ID、评论内容、评论时间,按需求选择就是了
try:
#获取评论总数
#通过xpath获取页面显示的评论数(一般与实际不相符,或多或少)
comment_sum=driver.find_element_by_xpath("/html/body/div[1]/div/div[4]/div/div[2]/div[1]/div/div/div/div/div[2]/div/ul/li[3]/a/span/span/span/em[2]").text
comment_sum = int(comment_sum)#转换类型,str→int
#爬取评论并储存列表
for i in range(100000):#循环10w次(微博评论超过5w页面基本都会崩溃,电脑配置问题,如果高一点的,可以把循环设置更高,以求爬全部评论)
tem=[]#临时存储列表
k=str(i+1)#转换类型,字符串合并需要str类型
#a:评论用户昵称+评论内容,通过xpath获取,xpath从网页复制
a=driver.find_element_by_xpath("/html/body/div[1]/div/div[4]/div/div[2]/div[1]/div/div/div/div/div[4]/div/div[2]/div[2]/div/div/div["+k+"]/div[2]/div[1]").text#评论用户名+评论
a_1=a.split(u":")[0]#截取评论用户昵称
a_2=a[a.find(u":")+1:len(a)]#截取用户评论内容
#d:评论用户url地址,通过xpath获取
d=driver.find_element_by_xpath("/html/body/div[1]/div/div[4]/div/div[2]/div[1]/div/div/div/div/div[4]/div/div[2]/div[2]/div/div/div["+k+"]/div[2]/div[1]/a[1]").get_attribute('href')#评论用户地址
#e:评论用户ID,,通过xpath获取,然后截取
e=driver.find_element_by_xpath("/html/body/div[1]/div/div[4]/div/div[2]/div[1]/div/div/div/div/div[4]/div/div[2]/div[2]/div/div/div["+k+"]/div[2]/div[1]/a[1]").get_attribute('usercard').split("=")[1]#评论用户id
#b:评论时间,因为一条评论具有多种展现形式,而评论时间是最受影响的一个,目前只找到用try嵌套的方式进行获取(xpath可能因为评论的内容及评论是否具有回复的情况而改变)
try:
b=driver.find_element_by_xpath("/html/body/div[1]/div/div[4]/div/div[2]/div[1]/div/div/div/div/div[4]/div/div[2]/div[2]/div/div/div["+k+"]/div[2]/div[2]/div[2]").text
except:
try:
b=driver.find_element_by_xpath("/html/body/div[1]/div/div[4]/div/div[2]/div[1]/div/div/div/div/div[4]/div/div[2]/div[2]/div/div/div["+k+"]/div[2]/div[3]/div[2]").text
except:
b=driver.find_element_by_xpath("/html/body/div[1]/div/div[4]/div/div[2]/div[1]/div/div/div/div/div[4]/div/div[2]/div[2]/div/div/div["+k+"]/div[2]/div[4]/div[2]").text
#将评论用户昵称、评论内容、评论用户url、评论用户ID、评论时间及所属KOL添加到临时存储列表tem中
tem.append(a_1)
tem.append(a_2)
tem.append(d)
tem.append(e)
tem.append(b)
#没爬取1w条评论会print出一次用户昵称(第N万个评论用户的昵称)
if int(k)%10000 == 0:
print tem[0]
time.sleep(1)
#将临时存储列表添加到评论存储列表中
res_PL.append(tem)
except:#如果i超过了评论大楼的最高楼层,则执行下面内容,表示该链接已爬完,并且print出-实际爬取数量 页面显示评论数 总爬取数据
print u"该链接已爬完"+" "+str(i)+" "+str(comment_sum)+" "+str(len(res_PL))#
driver.quit()#退出页面
最后就是写入文件了,写入文件有很多种方法,不过感觉最好用还是to_csv
columns_name = [u'评论用户昵称',u'评论内容',u'评论用户链接',u'评论用户ID',u'评论时间']#定义表头
res_tem = pd.DataFrame(columns=columns_name,data=res_PL)#定义表内容
res_tem.to_csv(u"C:\Users\Administrator\Desktop\评论用户数据.csv",encoding='utf_8_sig')#写入CSV文件并保存在桌面
回头说一下,我这里主要用到的定位方式:
1、class定位:find_element_by_class_name(self, name)
通过定位网页的class元素属性,只要你想定位的有class属性,你就可以通过class_name来定位,但是要注意一个页面中可能会存在多个同样class_name的元素,所以这种方式相对适合页面仅此一个class属性的元素
我们可以通过页面的开发者工具(点一下F12)来找到你所需的class_name。
2、xpath定位:find_element_by_xpath(self, xpath)
通过定位网页中的XML地址来定位元素,存在唯一性,就是只有你的xpath精准,不可能定位错,而且可通过迭代重复定位,获取所有评论的信息。若评论间的xpath存在差异,则需要通过尝试(try)获取所需内容
点击这个,然后找到我们需要获取的内容
鼠标放在需定位内容上,然后可以在右边看到信息对于的页面源码
然后右击页面源码→选择“复制”→选择“复制xpath”,然后就能得到页面信息的xpath,通过找到每条信息的逻辑,用迭代的方式找出各个评论的消息并获取
写在最后:
1、这是一个相对较笨的方法,但菜鸟是这样的啦,不要介意太多;
2、或者你们会问,为什么有些评论已评论的评论(拗口吗,希望你能懂)没被爬取,我只能说这是其中的一个缺陷吧,但其实这部分评论不多,忽略的话弊端应该不大(下次我更新一篇,然后那篇是把这部分也爬了的);
3、这个方法不仅笨,而且还有点慢(慢是和休眠时间有一定关系),1k条评论大概10分钟,1w条评论大概1小时,10w。。。我电脑配置不好,5w的量已经略卡了;
4、或者你们想问,微博好像封了我IP,我爬不了了,那我只能说你运气不太好,我这么就还没被封,要不你把休眠时间弄长一点试试,再不行就只能模拟登陆或者用代理了,但这个太高级,我还不会,去问度娘吧