今天我们进行的是微博移动端的评论爬取,将爬取的数据存放到excel表格中,这本来使件很容易的事情,结果我看很多博主都没有做,所以今天我们就来做一下吧。
这是我们今天要爬取的微博,人民日报每天都有几十条的微博输出,完全可以满足我们的要求,由于我们是使用的selenium框架爬取的微博评论,selenium最大的缺点就是出奇的慢,当然,selenium也有自己的优点,那就是所见其所得,操作简单,易上手。
我们知道微博的反爬能力还是很强的,他们有自己的一个反爬团队,所以我建议新手不要去尝试爬取网页端,先从容易的移动端做起就很好了。
接下来我们介绍爬取思路
要想爬取微博移动端的第一步就是先登录上去,那怎么解决这个登录问题呢?
?
登录手机微博可以通过输入手机号,获取验证码登录,或者通过用账号密码登录,但是他们在各自发送几次验证码之后就会提示今天的次数已经达到上限,所以我们不可能每次都要通过,输入验证码的形式登录。这时,cookies可以为我们解决登录问题。
cookies是什么?
cookies是发送第一次请求的时候,将共享数据发送到浏览器中进行保存,以后每次请求都会将共享数据发送到服务器,这也是为什么我们用浏览器可以直接登录的原因。
cookies虽好,但是具有一定的时效性,一段时间后可能就不能使用了,所以我们就要更换cookies。
如何获取cookeis?
获取cookies代码段
from selenium.webdriver import Firefox
import time
if __name__=='__main__':
web=Firefox()
#打开网址
web.get('https://m.weibo.cn/login?backURL=https%3A%2F%2Fm.weibo.cn%2F')
time.sleep(5)
#输入手机号
web.find_element_by_xpath('/html/body/div/div[1]/div/div/form/div/input').send_keys('你的手机号')
time.sleep(2)
#点击获取验证码
web.find_element_by_xpath('/html/body/div/div[1]/div/div/a').click()
time.sleep(30)
#这里要手动点击验证,输入验证码
cookie=web.get_cookies()
time.sleep(3)
print(cookie)
?获取到的cookie
之后我们就可以拿着cookies去登录了。
登录代码段
from selenium.webdriver import Firefox
import time
if __name__=='__main__':
web=Firefox()
#目标网址
web.get('https://m.weibo.cn/?sudaref=m.weibo.cn&display=0&retcode=6102')
time.sleep(1)
cookies ={'name': '_T_WM', 'value': '65791748215', 'path': '/', 'domain': '.weibo.cn', 'secure': False, 'httpOnly': False, 'expiry': 1630771201, 'sameSite': 'None'}, {'name': 'WEIBOCN_FROM', 'value': '1110006030', 'path': '/', 'domain': '.weibo.cn', 'secure': False, 'httpOnly': True, 'sameSite': 'None'}, {'name': 'SUB', 'value': '_2A25MN01wDeRhGeFL7VYQ9izIzDqIHXVv2FM4rDV6PUJbktCOLVXbkW1Nfc54NlnhyBWsRdhGK0hSNZNSrxkxgB2b', 'path': '/', 'domain': '.weibo.cn', 'secure': True, 'httpOnly': True, 'expiry': 1662283936, 'sameSite': 'None'}, {'name': 'SUBP', 'value': '0033WrSXqPxfM725Ws9jqgMF55529P9D9W5XQQxV.jJsdH2hb0UBBfNY5NHD95QNSKqXeKqEShMcWs4DqcjMi--NiK.Xi-2Ri--ciKnRi-zNS0-cSh2ceoBNSntt', 'path': '/', 'domain': '.weibo.cn', 'secure': True, 'httpOnly': False, 'expiry': 1662283936, 'sameSite': 'None'}, {'name': 'SSOLoginState', 'value': '1630747937', 'path': '/', 'domain': '.weibo.cn', 'secure': True, 'httpOnly': False, 'sameSite': 'None'}, {'name': 'XSRF-TOKEN', 'value': 'fb173e', 'path': '/', 'domain': '.m.weibo.cn', 'secure': False, 'httpOnly': False, 'expiry': 1630749197, 'sameSite': 'None'}, {'name': 'MLOGIN', 'value': '1', 'path': '/', 'domain': '.weibo.cn', 'secure': False, 'httpOnly': False, 'expiry': 1630751597, 'sameSite': 'None'}, {'name': 'M_WEIBOCN_PARAMS', 'value': 'lfid%3D102803%26luicode%3D20000174', 'path': '/', 'domain': '.weibo.cn', 'secure': False, 'httpOnly': True, 'expiry': 1630748597, 'sameSite': 'None'}
for cookie in cookies:
web.add_cookie(cookie)
time.sleep(1)
#一定要记得刷新
web.refresh()
?
将数据存放到excel表格代码段
excel_path = "D:\\移动" # 写入的excel文件路径
now_time = strftime("%Y-%m-%d-%H") # 获取时间戳为excel文件名和表名
# 创建excel追加数据到表中
class Write_Excel():
def __init__(self):
self.path = excel_path
self.name = now_time + ".xls"
self.filename = join(self.path, self.name)
# 设置表格样式
def set_style(self, name, height, bold=False):
style = xlwt.XFStyle()
font = xlwt.Font()
font.name = name
font.bold = bold
font.color_index = 4
font.height = height
style.font = font
return style
# 新建excel文件
def new_excel(self):
f = xlwt.Workbook()
f.add_sheet(now_time, cell_overwrite_ok=True) # 新增excel中表now_time
f.save(self.filename)
print("文件【%s】创建成功" % self.name)
# 对excel文件写入数据
def add_to_excel(self, values):
try:
workbook = xlrd.open_workbook(self.filename) # excel文件存在则直接打开
except FileNotFoundError: # excel文件不存在则先创建在打开
self.new_excel()
workbook = xlrd.open_workbook(self.filename)
sheets = workbook.sheet_names() # 获取工作簿中的所有表格
worksheet = workbook.sheet_by_name(sheets[0]) # 获取工作簿中所有表格中的的第一个表格
rows_old = worksheet.nrows # 获取表格中已存在的数据的行数
if rows_old == 0: # 跳过首行写入,留存为标题行
rows_old = 1
new_workbook = copy(workbook) # 将xlrd对象拷贝转化为xlwt对象,旧数据复制保存
new_worksheet = new_workbook.get_sheet(0) # 获取转化后工作簿中的第一个表格
i = 0
for value in values:
new_worksheet.write(rows_old, i, value) # 追加写入数据,从rows_old行开始写入
i += 1
print(" 文件【{0}】表【{1}】第【{2}】行追加数据{3}".format(self.name, now_time, rows_old, values))
# 定义标题行信息
title_row = ["名称", "位置", "申请者", "时间", " ", " ", " "]
for n in range(0, len(title_row)):
new_worksheet.write(0, n, title_row[n], self.set_style('Times New Roman', 220, True))
new_workbook.save(self.filename) # 保存excel文件
爬取数据代码段
from os.path import join
from time import strftime
import xlrd
import xlwt
from xlutils.copy import copy
from selenium.webdriver import Firefox
import time
from selenium.webdriver.common.action_chains import ActionChains
import driver
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import emoji
from re import sub
import emoji
import re
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
excel_path = "D:\\移动" # 写入的excel文件路径
now_time = strftime("%Y-%m-%d-%H") # 获取时间戳为excel文件名和表名
# 创建excel追加数据到表中
class Write_Excel():
def __init__(self):
self.path = excel_path
self.name = now_time + ".xls"
self.filename = join(self.path, self.name)
# 设置表格样式
def set_style(self, name, height, bold=False):
style = xlwt.XFStyle()
font = xlwt.Font()
font.name = name
font.bold = bold
font.color_index = 4
font.height = height
style.font = font
return style
# 新建excel文件
def new_excel(self):
f = xlwt.Workbook()
f.add_sheet(now_time, cell_overwrite_ok=True) # 新增excel中表now_time
f.save(self.filename)
print("文件【%s】创建成功" % self.name)
# 对excel文件写入数据
def add_to_excel(self, values):
try:
workbook = xlrd.open_workbook(self.filename) # excel文件存在则直接打开
except FileNotFoundError: # excel文件不存在则先创建在打开
self.new_excel()
workbook = xlrd.open_workbook(self.filename)
sheets = workbook.sheet_names() # 获取工作簿中的所有表格
worksheet = workbook.sheet_by_name(sheets[0]) # 获取工作簿中所有表格中的的第一个表格
rows_old = worksheet.nrows # 获取表格中已存在的数据的行数
if rows_old == 0: # 跳过首行写入,留存为标题行
rows_old = 1
new_workbook = copy(workbook) # 将xlrd对象拷贝转化为xlwt对象,旧数据复制保存
new_worksheet = new_workbook.get_sheet(0) # 获取转化后工作簿中的第一个表格
i = 0
for value in values:
new_worksheet.write(rows_old, i, value) # 追加写入数据,从rows_old行开始写入
i += 1
print(" 文件【{0}】表【{1}】第【{2}】行追加数据{3}".format(self.name, now_time, rows_old, values))
# 定义标题行信息
title_row = ["名称", "位置", "申请者", "时间", " ", " ", " "]
for n in range(0, len(title_row)):
new_worksheet.write(0, n, title_row[n], self.set_style('Times New Roman', 220, True))
new_workbook.save(self.filename) # 保存excel文件
if __name__ == "__main__":
# 模拟浏览器
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0'
opt = webdriver.FirefoxOptions()
opt.add_argument('--user-agent=%s' % user_agent)
web = webdriver.Firefox(executable_path='D:\\软件\\firefox\\geckodriver.exe', options=opt)
# 打开微博移动端
print('打开微博移动端')
web.get('https://m.weibo.cn/u/2803301701?uid=2803301701&t=0&luicode=10000011&lfid=100103type%3D1%26q%3D%E4%BA%BA%E6%B0%91%E6%97%A5%E6%8A%A5')
time.sleep(1)
cookies ={'name': '_T_WM', 'value': '65791748215', 'path': '/', 'domain': '.weibo.cn', 'secure': False, 'httpOnly': False, 'expiry': 1630771201, 'sameSite': 'None'}, {'name': 'WEIBOCN_FROM', 'value': '1110006030', 'path': '/', 'domain': '.weibo.cn', 'secure': False, 'httpOnly': True, 'sameSite': 'None'}, {'name': 'SUB', 'value': '_2A25MN01wDeRhGeFL7VYQ9izIzDqIHXVv2FM4rDV6PUJbktCOLVXbkW1Nfc54NlnhyBWsRdhGK0hSNZNSrxkxgB2b', 'path': '/', 'domain': '.weibo.cn', 'secure': True, 'httpOnly': True, 'expiry': 1662283936, 'sameSite': 'None'}, {'name': 'SUBP', 'value': '0033WrSXqPxfM725Ws9jqgMF55529P9D9W5XQQxV.jJsdH2hb0UBBfNY5NHD95QNSKqXeKqEShMcWs4DqcjMi--NiK.Xi-2Ri--ciKnRi-zNS0-cSh2ceoBNSntt', 'path': '/', 'domain': '.weibo.cn', 'secure': True, 'httpOnly': False, 'expiry': 1662283936, 'sameSite': 'None'}, {'name': 'SSOLoginState', 'value': '1630747937', 'path': '/', 'domain': '.weibo.cn', 'secure': True, 'httpOnly': False, 'sameSite': 'None'}, {'name': 'XSRF-TOKEN', 'value': 'fb173e', 'path': '/', 'domain': '.m.weibo.cn', 'secure': False, 'httpOnly': False, 'expiry': 1630749197, 'sameSite': 'None'}, {'name': 'MLOGIN', 'value': '1', 'path': '/', 'domain': '.weibo.cn', 'secure': False, 'httpOnly': False, 'expiry': 1630751597, 'sameSite': 'None'}, {'name': 'M_WEIBOCN_PARAMS', 'value': 'lfid%3D102803%26luicode%3D20000174', 'path': '/', 'domain': '.weibo.cn', 'secure': False, 'httpOnly': True, 'expiry': 1630748597, 'sameSite': 'None'}
for cookie in cookies:
web.add_cookie(cookie)
web.refresh()
time.sleep(10)
# 爬取微博评论
print('爬取微博评论')
var2=0
for i in range(4, 200000):
number1=int(i/10)
str1 = '/html/body/div/div[1]/div[1]/div[{}]/div/div/div/footer/div[2]/h4'.format(i)
try:
number_comment = web.find_element_by_xpath(str1).text
except:
print('没有对应微博')
continue
#var1_1判断是否带万
if number_comment == '评论':
print('无评论内容')
continue
var1_1=0
for k in range(1,len(number_comment)):
if number_comment[k]=='万':
var1_1=1
number_comments=10000
if var1_1==0:
number_comments=int(number_comment)
if number_comments <= 20:
print('评论数小于20')
continue
else:
for w in range(3):
# 第一个参数x是横向距离,第二个参数y是纵向距离
js = 'window.scrollBy(0, 600)' # 90表示滚动条下滑的长度(位置)
web.execute_script(js)
time.sleep(2)
# 点击进入微博评论
print('进入', i, '微博评论')
ele = web.find_element_by_xpath(str1)
web.execute_script('arguments[0].click()', ele)
time.sleep(4)
status = True
var1 = 0
time.sleep(3)
while status:
# 获取页面当前高度
js = "return action=document.body.scrollHeight"
height_1 = web.execute_script(js)
# 将滚动条调整至页面底部
time.sleep(2)
print('将滚动条调整至页面底部')
web.execute_script('window.scrollTo(0, document.body.scrollHeight)')
time.sleep(3)
# 获取页面现在的高度
js2 = "return action=document.body.scrollHeight"
height_2 = web.execute_script(js2)
time.sleep(1)
if height_1 == height_2 or var1 == 18:
# 跳出循环
status = False
else:
var1 = var1 + 1
# 爬取微博评论
print('爬取微博评论')
number_comments_2 = int(number_comments / 5)
for j in range(1, number_comments_2):
# 用户名
str2 = '/html/body/div/div[1]/div/div[4]/div[2]/div[{}]/div/div/div/div/div[2]/div[1]/div/div/h4'.format(j)
# 评论
str3 = '/html/body/div/div[1]/div/div[4]/div[2]/div[{}]/div/div/div/div/div[2]/div[1]/div/div/h3'.format(j)
try:
weibo_name = web.find_element_by_xpath(str2).text
weibo_comment = web.find_element_by_xpath(str3).text
except:
break
weibo_comment_end = re.sub('[a-zA-Z]', '', weibo_comment)
# 判断微博评论是否符合要求
if len(weibo_comment_end) >= 20:
weibo_sum = [weibo_name, weibo_comment_end]
# 输出结果
print(weibo_name, weibo_comment_end)
try:
Write_Excel().add_to_excel(values=weibo_sum)
except:
time.sleep(2)
continue
else:
print('长度不符合要求')
# 退出微博
time.sleep(3)
web.back()
time.sleep(2)
for w in range(3):
# 第一个参数x是横向距离,第二个参数y是纵向距离
js = 'window.scrollBy(0, 600)' # 90表示滚动条下滑的长度(位置)
web.execute_script(js)
time.sleep(2)
|