上一篇爬虫,真心慢,所以一直想研究一个新的方法,但对于我这种半路出家,只有一点Python基础就去自学爬虫的人来说,找一种新的方法是在有难度。
原本是想放下之前的所学,然后从新跟着《Python网络数据采集》来系统学习的,但是我发现自己实在静不下来
最后只好在之前的一条岔路上,继续走,看看能不能优化一下爬虫
系统学Python爬虫的都知道,bs4中的beautiful是很好用的一个爬虫方法,但其实webdriver中也有类似的方法
html = driver.page_source
这种方式也是会获取到整个页面源码,如果你print html一下,你会发现,咻的一声,页面源码全部出来
获取了全部的页面源码,那么我们就可以通过re里面的findall找出我们需要的信息咯(这个会把回复的评论也找出来)
此时此刻,先自问一下正则表达式学得怎么样,学得不太好的话,最好先去看看,了解了解基本逻辑
#昵称、链接、ID
html_list = re.findall('<a\s*target="_blank"\s*href="//weibo.com/[a-z0-9A-Z]*"\s*usercard="id=[0-9]*">.*?</a>',html,re.S)
#评论日期、时间
time_list = re.findall('<div\s*class="WB_from.S_txt2".{0,20}?div>',html,re.S)
#评论内容
comment_list = re.findall(u'</a>(?:\s*<i\s.*?></i>)?[\uff1a].*?</div>',html,re.S)
我详细说一下我用到的那3段正则表达式
第一段
html_list = re.findall('<a\s*target="_blank"\s*href="//weibo.com/[a-z0-9A-Z]*"\s*usercard="id=[0-9]*">.*?</a>',html,re.S)
其实通过开发者工具,我们都能看到,在一条评论中的的用户名字是包含了链接、ID以及昵称。
链接的组成是 href="//weibo.com/********" ,其中 * 的组成绝大部分都是数字,但是少数微博用户的是英文或者英文+数字
ID的组成是 usercard=“id=**********” ,其中 * 的组成为数字,至于位数一般为10位
昵称的组成其实是处于 <a></a> 之间的,作为微博(QQ微信等)的使用者,我们知道昵称的组成真的是“多姿多彩”的,所以我们过于强求把整个昵称(有些昵称可能包含了图片,虽然我不理解为什么可以这样命名)截取出来,我们只需要把其中的文字、数字字符截取就好
前面的re.findall就不说了,这是Python中re库的内置函数,具体的功能是寻找所有符合条件的源码
重点说一下中间的正则表达式
\s:不可见的字符,包括空格、换行符等等
*:0-无穷个
\s*:0-无穷个空格(换行符等)
[a-z0-9A-Z] :一个属于a-z或0-9或A-Z的字符
[a-z0-9A-Z]*:由0-无穷个属于a-z或0-9或A-Z的字符组成的字符串
[0-9]*:由0-无穷个属于0-9的字符组成的字符串
.:匹配除去换行符与回车符的任意一个字符
?:非贪婪匹配模式(可以理解为尽可能少的进行匹配,因为页面源码存在多个 </a> ,若使用贪婪匹配,会导致出一个开头为 <a**>,结尾为 </a> 的结果,中间存在多个<a></a>)
.*?:由0-无穷个字符组成字符串(非贪婪模式匹配,且不包含换行符及回车符)
第二段
time_list = re.findall('<div\s*class="WB_from.S_txt2".{0,20}?div>',html,re.S)
这是爬取时间用的正则表达式
从开发者工具我们可以看到所有的时间都是记录在 <div****>****</div> 里面的
这里只有一个新的正则表达式
.{0,20}?:其实和 .*? 的原理是差不多的,只是把 * 换成了 {0,20} ,就是把任意字符(不包含换行符回车符)非贪婪模式下匹配0-20次,也就是匹配一段长度为0-20之间的字符串
第三段
comment_list = re.findall(u'</a>(?:\s*<i\s.*?></i>)?[\uff1a].*?</div>',html,re.S)
这是爬评论的正则表达式,也是我自己都不确定是否已经完善的正则表达式(其实我的工作对这部分的要求并不大,但是本人有点完美主义,原本能爬的这部分,感觉不爬不舒服)
首先我们要了解我们需要爬取的评论形式以及评论的实际形式
一般我们需要的评论都是文字型的,因为文字型评论具有分词意义,当然有些可能需要图片型,但此处不作议论
微博的评论(其实不止微博)其实多种多样,有文字的,有图片的,有表情的等等
从开发者工具我们可以看到一般文字(包含英文数字中午及字符)评论都会存在于 > 和 < 之间,然后文字之间或者前后可能会穿插着图片 <img> ,这部分其实我们不需要,但截取的时候也不得不将其截取下来
经过细心的观察其实我们可以发现其实所有的评论(无论文字还是图片表情)其实都包含在 </a> 和 </div> 之间,但我们将这中间所有的字符通过非贪婪模式进行匹配,就可以把评论截取出来了
说说这段的正则表达式
(?:tem):非获取匹配,匹配tem但不获取结果,等待全部匹配结束后输出整个结果(why need?①)
[\uff1a]:中文符号中的引号“:”
①:目前发现在微博中的评论有一种叫做“微博监督员”的图标,这个图标的会影响到我们的匹配,因为它是介于 </a> 和引号:之间的,所以我们只能用这样的方式将其匹配出来,若有怎一并匹配,若无则跳过匹配。
接下来就是数据的整理了
res_list=[]
for i in range(len(html_list)):
tem=[]
tem_htm=html_list[i].split()[2].split('"')[1]
tem_ID=html_list[i].split()[3].split('"')[1].split("=")[1]
tem_name=html_list[i].split()[3].split('"')[2][1:(len(html_list[i].split()[3].split('"')[2]))-4]
tem_comment=re.sub('<.*?>','',comment_list[i])[1:]
try:
tem_date=time_list[i].split(">")[1].split("<")[0].split()[0]
tem_time=time_list[i].split(">")[1].split("<")[0].split()[1]
except:
tem_date=Date_Time
tem_time=time_list[i].split(">")[1].split("<")[0]
tem.append(tem_name)
tem.append(tem_ID)
tem.append("https:"+tem_htm)
tem.append(tem_comment)
tem.append(tem_date)
tem.append(tem_time)
res_list.append(tem)
这段代码挺简单的,只有一个需要注意的函数
“re.sub”
这是用来删除符合条件(正则表达式)的字符串,我这里是把所有 <**> 的内容通过非贪婪模式进行匹配并删除,这样就可以将评论中的图片表情图标等等都删除掉(包括前面的 </a> 和后面的 </div> )
最后的最后,附上所有的代码
from selenium import webdriver
import time
import re
import xlrd
import pandas as pd
fname=u"C:\\Users\\Administrator\\Desktop\***.xlsx"
bk=xlrd.open_workbook(fname)
x1=pd.ExcelFile(fname)#打开并读取文件内容
sh=bk.sheet_by_name(x1.sheet_names[0])#获取第一个sheet的内容
URL_list=[]
for i in range(sh.nrows-1):
URL_list.append(sh.cell(i+1,0).value)
js="var q=document.documentElement.scrollTop=100000"
res_PL = []
k = 0
for url in URL_list:
driver = webdriver.Firefox()
driver.get(url)
time.sleep(10)
Date_Time=time.strftime("%Y/%m/%d %H:%M:%S")
#将页面拖到底部
for i in range(5):
driver.execute_script(js)
time.sleep(2)
#查看更多直至全部显示
for i in range(10):
while (1):
try:
driver.find_element_by_class_name("more_txt").click()
time.sleep(0.8)
except:
break
time.sleep(2)
html = driver.page_source
#昵称、链接、ID
html_list = re.findall('<a\s*target="_blank"\s*href="//weibo.com/[a-z0-9A-Z]*"\s*usercard="id=[0-9]*">.*?</a>',html,re.S)
#评论日期、时间
time_list = re.findall('<div\s*class="WB_from.S_txt2".{0,20}?div>',html,re.S)
#评论内容
comment_list = re.findall(u'</a>(?:\s*<i\s.*?></i>)?[\uff1a].*?</div>',html,re.S)
res_list=[]
for i in range(len(html_list)):
tem=[]
tem_htm=html_list[i].split()[2].split('"')[1]
tem_ID=html_list[i].split()[3].split('"')[1].split("=")[1]
tem_name=html_list[i].split()[3].split('"')[2][1:(len(html_list[i].split()[3].split('"')[2]))-4]
tem_comment=re.sub('<.*?>','',comment_list[i])[1:]
try:
tem_date=time_list[i].split(">")[1].split("<")[0].split()[0]
tem_time=time_list[i].split(">")[1].split("<")[0].split()[1]
except:
tem_date=Date_Time
tem_time=time_list[i].split(">")[1].split("<")[0]
tem.append(tem_name)
tem.append(tem_ID)
tem.append("https:"+tem_htm)
tem.append(tem_comment)
tem.append(tem_date)
tem.append(tem_time)
res_list.append(tem)
res_PL.append(res_list)
k=k+len(res_list)
print u"该链接"+str(len(res_list))+u"条评论已爬完,共爬"+str(k)+u"条评论"
driver.quit()
import xlwt
filename=xlwt.Workbook(encoding='utf-8')#建立存储数据中转数据集
sheet=filename.add_sheet("res")#对sheet进行命名
zh=0#除去第一行已写入数据
for i in range(len(res_PL)):
for j in range(len(res_PL[i])):#分别for循环行数
for k in range(len(res_PL[i][j])):#分别for循环列数
sheet.write(zh,k,res_PL[i][j][k])#数据写入
zh+=1
#保存excel文件
filename.save("C:\\Users\\Administrator\\Desktop\\res.xls")
其余没做解释的代码可以参考我上一篇的爬虫或者是自己百度
亲测,爬虫速度快了很多,影响到你爬虫速度基本就是你自己的网速了
欢迎交流,有疑问请留言