尽管CSDN为创作者提供了数据观星,可以非常便捷地查看最近的创作情况,但是并没有提供文章间的对比,也没有更详尽的分析功能。所以本文通过selenium对博客的阅读量等内容进行爬取。
获取所有博文
这个功能是比较容易实现的,按理说一个人的所有文章都在博客主页,每篇文章的标题大致如下
<div class="blog-list-box-top" data-v-6fe2b6a7>
<h4 data-v-6fe2b6a7>Python标准库32个模块的整理</h4>
</div>
文章标题为Python标准库32个模块的整理
,其class
为blog-list-box-top
。
接下来通过selenium进入个人主页。
from selenium import webdriver
url = 'https://tinycool.blog.csdn.net/?type=blog'
driver = webdriver.Edge()
driver.get(url)
然后查找class
,如果使用find_element的方法,则只显示第一个匹配对象,
>>> Title = driver.find_element_by_class_name('blog-list-box-top')
>>> print(Title.text)
QT调用外部程序
如果采用find_elements
,则可定位所有文章,
>>> titleClass = 'blog-list-box-top'
>>> for T in driver.find_elements_by_class_name(titleClass):
... print(T.text)
...
QT调用外部程序
#。。。
从而得到当前页所有文章的标题,然而这个页面是那种无限滚动的,所以先滚动一下试试
driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")
可以通过对比文章数量和标题数量,来判断是否已经滚动到底,其中文章数位于
<li data-v-bb5f5e3e="" class="active"><!---->文章·<span class="nav-li-num" data-v-bb5f5e3e="">197</span></li>
可见文章这两个字在<li>
中,nav-li-num
这个class中直接就是文章的数量。
from selenium import webdriver
url = 'https://tinycool.blog.csdn.net/?type=blog'
driver = webdriver.Edge()
driver.get(url)
nArticles = driver.find_elements_by_class_name('nav-li-num')[0].text
nArticles = int(nArticles)
接下来只需对比当前滚动的位置是否有足量的Title,
import time
titleClass = 'blog-list-box-top'
scriptDown = "window.scrollTo(0,document.body.scrollHeight)"
scriptUp = "window.scrollTo(0,-500)"
Titles = driver.find_elements_by_class_name(titleClass)
while len(Titles) < nArticles:
driver.execute_script(scriptUp)
time.sleep(1) #发出命令后等待1秒
driver.execute_script(scriptDown)
time.sleep(1)
Titles = driver.find_elements_by_class_name(titleClass)
运行结束后,获取了237篇博客。
>>> len(Titles)
237
而博客链接被存放在一个a标签中
<a data-v-6fe2b6a7="" href="https://blog.csdn.net/m0_37816922/article/details/122035260?spm=1001.2014.3001.5502" target="_blank" data-report-click="{
"spm":"3001.5502"}" data-report-query="spm=3001.5502"><div data-v-6fe2b6a7="" class="blog-list-box-top"><h4 data-v-6fe2b6a7="">【C标准库】get和put</h4></div> </a>
为了获取链接,可以先复制一下这个a标签的完整Xpath,得到
/html/body/div[2]/div/div[1]/div/div/div/div/div/div[2]/div/div[2]/div/div[2]/div/article[1]/a
然后获取所有a标签所对应的链接,需要注意,刚刚获取的xpath仅仅是一篇文章的,所以article
后面有一个[1]
,在下面的代码中,去掉这个[1]
,可以获取当前页面上的所有这个路径下的a
标签,然后再提取出a
标签中的href
就行了
xpath = '/html/body/div[2]/div/div[1]/div/div/div/div/div/div[2]/div/div[2]/div/div[2]/div/article/a'
links = driver.find_elements_by_xpath(xpath)
links = [L.get_attribute('href') for L in links]
爬取数据
在得到所有的链接之后,就能摘取每篇文章的信息了。
在主页,除了标题之外还有阅读量、点赞和评论
<div data-v-6fe2b6a7="" class="view-num-box">
<span data-v-6fe2b6a7="" class="view-num">
91<span data-v-6fe2b6a7="" class="two-px"> 阅读 ·</span>
</span>
</div>
<div data-v-6fe2b6a7="" class="give-like-box">
<span data-v-6fe2b6a7="" class="give-like-num">
5<span data-v-6fe2b6a7="" class="two-px"> 点赞 ·</span>
</span></div>
<div data-v-6fe2b6a7="" class="comment-box">
<span data-v-6fe2b6a7="" class="comment-num">0<span data-v-6fe2b6a7="" class="two-px"> 评论</span>
</span>
</div>
而进入文章后,则可以更加方便地获取发布时间、阅读量、和收藏量。
<div class="bar-content">
<span class="time">于 2021-10-24 11:13:03 发布</span>
<span class="read-count">15086</span>
<span class="name">收藏</span>
<span class="get-collection">
584
</span>
故而在主页可爬取点赞数,由于数量和描述之间有一个空格,可split之后再转化为数字。
titleClass = 'blog-list-box-top'
likeClass = 'give-like-num'
Titles = [t.text for t in driver.find_elements_by_class_name(titleClass)]
Likes = [int(L.text.split(' ')[0]) for L in driver.find_elements_by_class_name(likeClass)]
在文章内容里,标题位于h1
中的title-article
类;阅读量为read-count
类的一个span。比较尴尬的是我选的这篇文章竟然没人收藏。不得已打开一个有收藏的文章,发现收藏数被放在一个get-collection
的span中,则按照此前的方法不难得到各种信息
infoDict = {
"title":'title-article',
"time":"time",
"read":'read-count',
"collection":'get-collection'}
getElement = lambda value : driver.find_element_by_class_name(value)[0].text
tmp = {
key:getElement(infoDict[key]) for key in infoDict}
从而得到
{'title': '【C标准库】stdio.h', 'time': '2021-12-20 11:46:45', 'read': '6', 'collection': ''}
接下来可以逐一对所有的链接执行此项操作
infos = []
for url in links:
driver.get(url)
infos.append({
key:getElement(infoDict[key]) for key in infoDict})
最后将Likes
写入infos
likeDict = {
Titles[i]:Likes[i] for i in range(len(Titles))}
for info in infos:
info['like'] = likeDict[info['title']]
在爬取完成后,将infos
写入csv
import csv
f = open('blogs.csv','w',newline='')
w = csv.writer(f)
for info in infos:
w.writerow(list(info.values()))
f.close()
所有代码
获取文章数
from selenium import webdriver
url = 'https://tinycool.blog.csdn.net/?type=blog'
driver = webdriver.Edge()
findClass = driver.find_elements_by_class_name
driver.get(url)
num = int(findClass('nav-li-num')[0].text)
接下来进入循环,得到所有页面的链接
import time
titleClass = 'blog-list-box-top'
likeClass = 'give-like-num'
scriptDown = "window.scrollTo(0,document.body.scrollHeight)"
scriptUp = "window.scrollTo(0,-500)"
Titles = findClass(titleClass)
while len(Titles) < num:
driver.execute_script(scriptUp)
time.sleep(1) #发出命令后等待2秒
driver.execute_script(scriptDown)
time.sleep(1) #发出命令后等待2秒
Titles = findClass(titleClass)
Titles = [t.text for t in findClass(titleClass)]
Likes = [L.text.split(' ')[0] for L in findClass(likeClass)]
xpath = '/html/body/div[2]/div/div[1]/div/div/div/div/div/div[2]/div/div[2]/div/div[2]/div/article/a'
links = driver.find_elements_by_xpath(xpath)
links = [L.get_attribute('href') for L in links]
进入每个页面,并获取我们需要的信息
infoDict = {
"title":'title-article',
"time":"time",
"read":'read-count',
"collection":'get-collection'}
infos = []
for url in links:
driver.get(url)
infos.append({
key:findClass(infoDict[key])[0].text for key in infoDict})
likeDict = {
Titles[i]:Likes[i] for i in range(len(Titles))}
for info in infos:
info['like'] = likeDict[info['title']]
# 将时间和日期分开
for info in infos:
dt = info['time'].split(" ")
info['date'] = dt[1]
info['time'] = dt[2]
import csv
f = open('blogs.csv','w',newline='')
w = csv.writer(f)
for info in infos:
w.writerow(list(info.values()))
f.close()
分析
获取这些数据之后,就可以进行分析了,例如想知道阅读量和收藏量的关系,如下图所示
阅读量和点赞量之间的关系
可见每100个阅读,有1.3人收藏,而只有0.45人点赞,可见相对于点赞,大家还是喜欢收藏的。
由于评论人数实在太少,就没爬取。
也可以更加直观地查看每篇博客的阅读量,横轴为博客发布的时间顺序。
所以比较希望这些尖尖的部分再多一些哈。