栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【网络爬虫

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【网络爬虫

# 正则表达式 通过视频 bv 号获取 oid self.oid re.findall( aid :([0-9]*), , response)[0]

        请求函数需要传递url page 最大页面数

        通过requests库请求数据 需要的数据都在data- replies里面

​​

 def content_get(self, url, page):
 now 0 # 当前页面
 while now page:
 print( page : {now} / {page} .format(now now, page page))
 response requests.get(url url str(now), cookies self.cookies, headers self.headers, timeout 10).json() # 把response解析为json格式 通过字典获取
 replies response[ data ][ replies ] # 评论数据在data- replies 里面 每页有 20 条
 now 1
 for reply in replies: # 遍历获取每一条 用reply_clean函数提取数据
 line self.reply_clean(reply)
 self.count 1

        我们预先定义一个reply_clean函数 用来提取数据

         2.数据清洗

        reply里面的数据很多 但大多数对我们来说都是没有用的。

 def reply_clean(self, reply):
 name reply[ member ][ uname ] # 名字
 sex reply[ member ][ sex ] # 性别
 if sex 保密 :
 sex 
 mid reply[ member ][ mid ] # 帐号的uid
 sign reply[ member ][ sign ] # 标签
 rpid reply[ rpid ] # 爬二级评论要用到
 rcount reply[ rcount ] # 回复数
 level reply[ member ][ level_info ][ current_level ] # 等级
 like reply[ like ] # 点赞数
 content reply[ content ][ message ].replace( n , ) # 评论内容
 t reply[ ctime ]
 timeArray time.localtime(t)
 otherStyleTime time.strftime( %Y-%m-%d %H:%M:%S , timeArray) # 评论时间 时间戳转为标准时间格式
 return [count, name, sex, level, mid, sign, otherStyleTime, content, like, rcount, rpid]

 评论时间为时间戳 用time库把时间戳转换为给人看的时间格式。

 到此处 我们已经获取到了一级评论 并把数据返回为列表类型

        3.数据获取 # 二级评论

为了增加代码的复用性 我们可以改变一下上面两个函数

 # level_1判断是否为一级评论。如果为二级评论 则不请求下一级评论 评论的评论 
 def content_get(self, url, page, level_1 True):
 now 0
 while now page:
 print( page : {now} / {page} .format(now now, page page))
 response requests.get(url url str(now), cookies self.cookies, headers self.headers, timeout 10).json()
 replies response[ data ][ replies ] # 评论数据在data- replies 里面 一共有 20 条
 now 1
 for reply in replies:
 if level_1:
 line self.reply_clean(reply, self.count)
 self.count 1
 else:
 line self.reply_clean(reply)
 self.q.put(line)
 # 这儿我们可以筛选一下 如果一级评论有跟评 调用函数请求二级评论
 if level_1 True and line[-2] ! 0:
 # root表示rpid。在二级评论api中是root参数。page页数 由于我们把最大显示量设置为20 所以除以20。加0.5向上取整
 self.content_get(url self.rreplyUrl.format(root str(line[-1])), page int(line[-2]/20 0.5), level_1 False) # 递归获取二级评论
 

 我们通过传递给content_get的url参数 可以分别请求一级或二级评论。 而两种评论的json格式是完全一样的。都在data- replies中。self.count参数表示主楼数

        4.数据清洗 # 二级评论
 # 这个函数可以爬一级评论也能爬二级评论
 # count 参数 看看是不是二级评论。
 def reply_clean(self, reply, count False):
 name reply[ member ][ uname ] # 名字
 sex reply[ member ][ sex ] # 性别
 if sex 保密 :
 sex 
 mid reply[ member ][ mid ] # 帐号的uid
 sign reply[ member ][ sign ] # 标签
 rpid reply[ rpid ] # 爬二级评论要用到
 rcount reply[ rcount ] # 回复数
 level reply[ member ][ level_info ][ current_level ] # 等级
 like reply[ like ] # 点赞数
 content reply[ content ][ message ].replace( n , ) # 评论内容
 t reply[ ctime ]
 timeArray time.localtime(t)
 otherStyleTime time.strftime( %Y-%m-%d %H:%M:%S , timeArray) # 评论时间 时间戳转为标准时间格式
 # 如果是二级评论 则返回数据第一个为 回复 否则为楼号
 # 二级评论没有回复数rcount 三级评论都显示为 回复xxx 谁谁谁
 if count:
 return [count, name, sex, level, mid, sign, otherStyleTime, content, like, rcount, rpid]
 else:
 return [ 回复 , name, sex, level, mid, sign, otherStyleTime, content, like, , rpid]

 

三、数据存储

数据存储选取了两种方式作为安全 csv和mysql数据库

1、csv

        用csv模块 while True重复读取队列元素。如果10秒钟还没有数据进来 说明爬完了 或者程序死了。不管是反爬死了还是咋死了 反正它死了

import csv
 def csv_writeIn(self, BV):
 file open( bilibili评论_ BV .csv , w , encoding utf-8 , newline )
 f csv.writer(file)
 line1 [ 楼层 , 姓名 , 性别 , 等级 , uid , 个性签名 , 评论时间 , 评论内容 , 点赞数 , 回复数 , rpid ]
 f.writerow(line1)
 file.flush()
 while True:
 try:
 line self.q.get(timeout 10)
 except:
 break
 f.writerow(line)
 file.flush()
 file.close()

执行一下 打开csv文件

 我们发现 csv乱码。这是因为 csv默认打开编码方式为ANSI 而我们是用utf-8存储的

这时候我们可以选择用记事本打开 另存为ANSI编码 再用csv打开

   ​

2、mysql
import pymysql as pysql
 def mysql_connect(self, host, user, password, BV):
 # 连接数据库 如果失败退出程序
 try:
 self.conn pysql.connect(host host, user user, password password)
 self.cursor self.conn.cursor()
 except:
 print( mysql connect error ... )
 exit(1)
 # 创建库 创建表
 self.cursor.execute( create database if not exists bilibili )
 self.cursor.execute( use bilibili )
 sql 
 create table if not exists {BV} (
 floor char(6),
 name char(20),
 sex char(2),
 level char(1),
 uid char(10),
 sign char(100),
 time char(23),
 content char(100),
 star char(6),
 reply char(6),
 rpid char(10))
 self.cursor.execute(sql.format(BV BV)) # 用视频BV号创建表
 def mysql_writeIn(self, BV):
 sql insert into BV
 ( floor , name , sex , level , uid , sign , time , content , star , reply , rpid ) value
 ( {floor} , {name} , {sex} , {level} , {uid} , {sign} , {t} , {content} , {star} , {reply} , {rpid} ) 
 sql sql.replace( BV , BV)
 # 用另一个线程写入表 设置timeout失败退出。
 while True:
 try:
 line self.q.get(timeout 10)
 except:
 self.conn.close()
 break
 # 由于数据长度是固定长度 有可能出现太长了写不进去的情况。这里根据实际需要 创建表的时候注意一个。实在太长就不要了吧哈哈哈哈
 try:
 self.cursor.execute(sql.format(floor line[0], name line[1], sex line[2], level line[3], 
 uid line[4], sign line[5], t line[6], content line[7], 
 star line[8], reply line[9], rpid line[10]))
 except Exception as e:
 print(e)
 continue
 # 记得提交 不然白存
 self.conn.commit()
四、多线程

        我们需要通过函数调用上面几个部分。多线程这里我们使用threading模块的Thread类构造

         各模块由main函数调用。

from threading import Thread
 def main(self, page, BV):
 self.mysql_connect(host localhost , user root , password SpiderXbest , BV BV)
 T []
 T.append(Thread(target self.content_get, args (self.replyUrl, page)))
 T.append(Thread(target self.mysql_writeIn, args (BV, )))
 # T.append(Thread(target self.csv_writeIn, args (BV, )))
 # 二选一 要么csv要么mysql
 print( 开始爬取... )
 for t in T:
 t.start()
 for t in T:
 t.join()
五、综合。
if __name__ __main__ :
 cookie fingerprint cdc14f481fb201fec2035d743ff230b; buvid_fp DE7C7303-E24E-462C-B112-EE78EB55C45B148824infoc; buvid_fp_plain 1BC352F4-4DB9-D82C-44A2-FB17273D240infoc; b_ut i-wann-go-back _uuid 43C8466C-79D5-F07A-032C-F6EF1635706854601infoc; buvid3 DE703-E24E-462C-B112-EE78EB55C45B148824infoc; CURRENT_FNVAL blackside_state sid 7wo01l; rpdid |(u)mmY|~YJ|0J uYJklJ~ul|; CURRENT_QUALITY 112; PVID bfe_id cade759d3229a3973a5d4e9161f3bc; innersign 1 
 cookies {}
 for c in cookie.split( ):
 b c.split( )
 cookies[b[0]] b[1]
 BV BV14h411n7ok 
 bilibili Bilibili(BV, 0, cookies, 1)
 bilibili.main(1, BV)

 在传递cookie的时候 最好把它变成字典格式。

 运行一下程序 爬一页试试

 ​

 ok 成功了我们只爬取一页 拨心回复只有最多20条。具体一个视频有多少页呢 我们在浏览器中请求一级评论url看看

 

 

 ​

 

 

 冰冰姐这个视频有一万多一点评论 到370页的时候就不动了。所以我们可以手动二分法看看具体有多少页 或者写一个判断函数 当请求函数content_get的replies为null的时候 说明结束了。

 

六、完整代码
# -- coding: utf-8 --
# Author : 竹一
# Time : 2021/9/25 10:37
# version : 1.0
# Software: PyCharm
import requests
import re
import time
from fake_useragent import UserAgent
import queue
import csv
import pymysql as pysql
from threading import Thread
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/267477.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号