前言
上一篇文章以老崔的微博(https://m.weibo.cn/u/2830678474)为例,讲述了采用网站本身的API如何爬取微博的方法,这一篇我将谈一谈采用selenium+无头浏览器 (chrome). 如何爬取微博的内容、发布时间,点赞数、评论数、转发数,并将它们保存到CSV文件。
本文以蔡徐坤的微博(https://weibo.com/caizicaixukun?profile_ftype=1&is_all=1#_0) 为爬取对象,由于笔者也很好奇她们家坤坤在微博到对火到什么程度,所以在文末会附上笔者自己对爬取的数据分析之后的一些结论。
下期预告:
江湖传言,不爬美图的爬虫不是一个优秀的爬虫,是没有灵魂的爬虫,所以下一期将会谈一谈如何利用selenium+无头浏览器爬取头条街拍网站的所有图片。
Selenium和无头浏览器简介
Selenium最初是用来自动化测试网站的工具,而爬虫主要是用它来爬取动态网页。因为采用Selenium驱动无头浏览器之后,可以得到所有的javascript运行之后的网页代码。所以能做到可见即可爬。
Selenium可以获取网页请求、模拟鼠标键盘的操作、通过一些标签的值(主要是id或者class)或者采用Xpath来查找网页标签、获取标签属性等等。
页面分析
最初我打算按照上一篇文章:
超神之路996:Python爬虫小试牛刀系列之爬取微博zhuanlan.zhihu.com里面的方式,看看有没有现成可用的API。在页面按F12打开浏览器的开发者工具,选择network选项卡,再选择XHR为过滤条件(只显示javascript发出的请求),刷新一下页面。相关最有可能的XHR请求是getdashinfo?,但是查看获取的响应,发现无法与页面的微博一一对应,所以断定蔡徐坤的微博更新页面的方式可能和老崔的不一样。当把蔡徐坤的微博页面拉到最下出现了图 2中的元素,这就更加证实了我的判断。老崔的微博拉到底是不会出现“下一页”这种元素的。
![0c9e7878aa6eb4ed2f11d0f13bde440a.png](https://i-blog.csdnimg.cn/blog_migrate/1a54fb0c4b43c50c04509dc11e935835.jpeg)
图 1
![5c0e147fa9b7909920e4ea63f3dcfb8e.png](https://i-blog.csdnimg.cn/blog_migrate/a0f57a26fbc1fb39df163b7fb3dec558.jpeg)
图 2
![0ccacb2eb9ec2226e872e2f65c3c61b2.png](https://i-blog.csdnimg.cn/blog_migrate/671223319d88b88a889854b6c33d271b.jpeg)
图 3
将浏览器开发工具的选项卡打到“Elements”查看网页源码,发现有很多的javascript程序,我猜他们的功能就是用来更新页面的,但是我研究了很久也没有搞明白是怎么更新的,如有知道的大神,请赐教。
但幸运的是,不知道代码逻辑并不影响我们爬取数据,采用Selenium+无头浏览器的方式最大的优点即在于此。
![29747535db5f52236a83118d5e9574a5.png](https://i-blog.csdnimg.cn/blog_migrate/48cab6640bdf05c3ba119d7d5bf5261b.png)
图 4
继续分析页面发现图 4的div标签与微博内容一一对应,我们所需要的信息都包含在里面。我们所需要做的就是爬取所有页面的所有类似div标签的中信息,那么如何获取所有页面的url呢?
将页面拉到底以后,发现图 5中左边有13个li标签对,正好与图 5右边的13页的微博也面对应,至此页面分析完毕。
但是还有一个问题需要解决,就是初始页面只会显示10微博,但是一个完整的页面总共有50条微博。需要不断将初始页面下拉才回得到一个完整的页面,这个功能可以如下实现:
def tingzhi(url):
broswer.get(url)
sleep(1)
i=0
while len(broswer.find_elements(By.XPATH,"//div[@action-type='feed_list_page_morelist']"))==0://当找到图 2中的元素时,就证明页面已经拉到底了,则循环停止
broswer.execute_script('window.scrollTo(0,%d)'%(1000000*i))
i=i+1
![192437bdd086c4ab362c04f85d7e1a76.png](https://i-blog.csdnimg.cn/blog_migrate/d599a71c4f2b44c76e7321cb2faa10c9.jpeg)
图 5
思路
分成两个步骤,
- 获取所有页面的url
- 解析所有条目,获取我们想要的内容
但是在采用broswer请求蔡徐坤微博页面的时候总是跳到微博的登录界面,原本打算采用Selenium自动登录,但是比较尴尬的是pytesseract库始终无法识别验证码,总后不得已采用粗暴原始的方法,sleep(20),让程序停止20秒,手工输入验证码。。。。
如有大神知道如何提高pytesseract库的识别率的方式,也请一并赐教。
![1e0b7cc713fc2c583a378d08d5481e49.png](https://i-blog.csdnimg.cn/blog_migrate/80e5d140a05fc9c4e91572a806400232.jpeg)
图 6
完整的代码如下
其中,youraccount和yourpassword是根据用户的不同,需要替换的。
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver import ActionChains
from selenium.webdriver import ChromeOptions
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from time import sleep
from bs4 import BeautifulSoup
import datetime
import re
import operator
import csv
# import pytesseract
# # from PIL import Image
# # import requests
options=ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
broswer=webdriver.Chrome(executable_path=r"C:UsershpAppDataLocalGoogleChromeApplicationchromedriver.exe",chrome_options=options)
script = '''Object.defineProperty(navigator, 'webdriver', {get: () => undefined})'''
broswer.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": script})
broswer.get("https://weibo.com/")
wait=WebDriverWait(broswer,10)
account=wait.until(ec.presence_of_element_located((By.ID,"loginname")))
sleep(0.5)
account.clear()
account.send_keys(youraccount)
passwd=broswer.find_element(By.XPATH,"//input[@type='password']")
sleep(0.5)
passwd.clear()
passwd.send_keys(yourpassword)
imgexist=wait.until(ec.presence_of_element_located((By.XPATH,"//img[@action-type='btn_change_verifycode']")))
surebt=broswer.find_element(By.XPATH,"//a[@suda-data='key=tblog_weibologin3&value=click_sign']")
surebt.click()
sleep(20)
def tingzhi(url):
broswer.get(url)
sleep(1)
i=0
while len(broswer.find_elements(By.XPATH,"//div[@action-type='feed_list_page_morelist']"))==0:
broswer.execute_script('window.scrollTo(0,%d)'%(1000000*i))
i=i+1
def timelist(text):
thisyear=str(datetime.date.today()).split("-")[0]
aa=re.findall(r'[u4e00-u9fa5]+',text)
if len(aa)!=0:
text=thisyear+" "+text
for item in aa:
text=re.sub(item," ",text)
text = re.sub(" +", " ", text)
timelist=text.split(" ")
else:
bb=re.findall(r'-',text)
for item in bb:
text=re.sub("-"," ",text)
text=text[1:]
text=re.sub(" +"," ",text)
timelist=text.split(" ")
return timelist
# def qx(text):
# 输出['小', '明']
tingzhi("https://weibo.com/caizicaixukun?profile_ftype=1&is_all=1#_0")
bsobj=BeautifulSoup(broswer.page_source,"html5lib")
lilist=bsobj.find("div",{"action-type":"feed_list_page_morelist"}).findAll("li")
urllist=[]
qz="https://weibo.com"
for item in lilist:
urllist.insert(0,qz+item.find("a").attrs["href"])
# 内容,发布时间(年-月-日,时间),转发数,评论数,点赞数
result_dict={}
index=1
for url in urllist:
tingzhi(url)
html=broswer.page_source
bsobj=BeautifulSoup(html,"html5lib")
wblist=bsobj.findAll("div",{"action-data":"cur_visible=0"})
for wb in wblist:
result_dict[index]=[]
content=wb.find("div",{"class":"WB_text W_f14"}).get_text()
content=re.sub(" +","",content)
retime=wb.find("div",{"class":"WB_from S_txt2"}).find("a").get_text()
retime=timelist(retime)
taillist=wb.find("div",{"class":"WB_feed_handle"}).findAll("li")
gd=[]
for tail in taillist[1:]:
gd.append(tail.findAll("em")[1].get_text())
result_dict[index].append(content)
result_dict[index]=result_dict[index]+retime+gd
print(result_dict[index])
index=index+1
result_list=sorted(result_dict.items(),key=operator.itemgetter(0),reverse=False)
csvfile=open("G:游戏蔡徐坤.csv","w+",encoding="utf-8-sig")
writer=csv.writer(csvfile,lineterminator="n")
writer.writerow(("序号","内容","发布年","发布月","发布日","发布时间","转发数","评论数","点赞数"))
for item in result_list:
writer.writerow((item[0], item[1][0], item[1][1],item[1][2], item[1][3], item[1][4], item[1][5], item[1][6],item[1][7]))
结果分析
![b6910e66f46357ea17a93e19f9a44282.png](https://i-blog.csdnimg.cn/blog_migrate/15f64e7d42cb2826c0eb39cd6268b3df.png)
图 7
从图 7可以看出,从2018年开始蔡徐坤的微博数量和条均点赞数都有了一个巨大的提升,这难道是他是从2018年开始火的?作为钢铁直男的笔者表示,第一次蔡徐坤这个名字是腾讯选他作为NBA形象大使的时候。
![b72a9b94f9e8f6fd276ed8a33788b63d.png](https://i-blog.csdnimg.cn/blog_migrate/209c3fb8a772d357ec8cdc36f44e8588.png)
图 8
从图 8可以看出在二月和六月蔡徐坤一般发微博数量比较少,二月一般是春节,六月猜测可能是放暑假??
![72da1263b2bd4a7117a998e4527f7de0.png](https://i-blog.csdnimg.cn/blog_migrate/626fc922aabcd9972009ab3de3ae0d09.png)
图 9
从图 9可以看出,他的微博发布时间多在下半天(艺人作息问题?),熬夜(0-6)发布的微博有39条,这比例处于合理范围内。
![3fe9f0d6f98c4f2f36cfdc2421205ef3.png](https://i-blog.csdnimg.cn/blog_migrate/14a7db6288c04e19f2b067a34a3c13b0.png)
图 10
从图 10可以看出其微博转发、评论、点赞超过100万很常见,证明确实是微博流量小生。他发布的585条微博一共被点赞375763589次,其中点赞最多的是2019年12月25发布的,如图 11。转发、评论数双双破100万,点赞数更是达到了8257896次。请问这条微博背后有什么故事吗。。。
![23eccae4140b9ed43c132f470b97387d.png](https://i-blog.csdnimg.cn/blog_migrate/ee29a2e1865a3d498f4ffdf965a1fb26.jpeg)
图 11