typora-root-url | typora-copy-images-to |
---|---|
爬虫\images |
爬虫\images |
静态网页:request请求的就是当前url
动态网页:需要进行抓包处理。
判断条件
使用查看网页源代码:页面当中的数据在网页源代码中有,那就是静态的,否则的就是需要动态抓包处理。
参考网站
教学
https://www.bilibili.com/video/BV1fJ411J719?from=search&seid=15740661422866602053
步骤
看是否动态网页 检查源代码和网页有些话是否出现,出现在源代码中就是静态页面
判断哪个包传的。
因此我们需要抓包,包地址和你正常访问地址很有可能不一样。
微博好像是静态页面
对于请求头
User-Agent
cookie
数据格式是unicode编码
数据解析
视频数据需要:获得title
得到的json数据
如何获得视频尾缀
直接拼接
import requests
import json
base_url='https://haokan.baidu.com/videoui/api/videorec?tab=gaoxiao&act=pcFeed&pd=pc&num=20&shuaxin_id=1612276740204'
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',
'Cookie': 'BIDUPSID=8303CDB62079598D55280B09241EC6A5; PSTM=1609205633; BAIDUID=8303CDB62079598D785D47E1C310AF5F:FG=1; ab_jid=e8f37dcb0d84ebde578eaeb4c81de8c0ef8e; ab_jid_BFESS=e8f37dcb0d84ebde578eaeb4c81de8c0ef8e; BAIDUID_BFESS=8303CDB62079598D785D47E1C310AF5F:FG=1; BDUSS=VkM29seVBtNW9BY35hdk80YzV4MXIyaS1UOWJPMnFnU2lmZ0tjak05TlZreDVnRVFBQUFBJCQAAAAAAAAAAAEAAADGgNJFysXLrsH3xOqy0NK5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUG919VBvdfTE; BDUSS_BFESS=VkM29seVBtNW9BY35hdk80YzV4MXIyaS1UOWJPMnFnU2lmZ0tjak05TlZreDVnRVFBQUFBJCQAAAAAAAAAAAEAAADGgNJFysXLrsH3xOqy0NK5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUG919VBvdfTE; H_PS_PSSID=33425_33581_33257_33273_31660_33594_33339_26350_33264; BA_HECTOR=85010120a4058h81331g1ilep0r; __yjs_duid=1_f17eb43300edc3f1cb0b26e84be486ad1612274351261; ab_sr=1.0.0_M2NkNDA5MTRmZWM0MDlmMzczMmQ2MmNiM2QxZGE2ZDcwYWE1MWE5MmM5YmY1YTc5YTFmYWMxYjdlNzNiM2MzYmRhYjg4M2MzMjM4ZTc1YjQ0NGFmYjliMjk4ZDU0YWM4'
}
# 发送请求
response = requests.get(base_url, headers=headers)
data = response.text
# print(data)
# 数据转换 把json字符串转换为python可以交换的类型
import json
json_data = json.loads(data)
# 数据解析 看你需要什么数据
# 一层层获得数据 网站json.cn可视化json
# 解析title,视频数据url类型(猜测)
data_list = json_data['data']['response']['videos']
# 遍历列表
for data_item in data_list:
# print(data_item)
# 视频文件名字 需要自己加尾缀
video_title=data_item['title']+'.mp4'
# 视频存在位置
video_Url = data_item['play_url']
# print(video_title)
print('正在下载',video_title)
# 再次发送具体视频URL地址 得到的是二进制数据,需要后面加上一个content
video_data = requests.get(video_Url,headers=headers).content
# 保存在文件夹videos,wb方式写入,二进制方式
with open('videos\\'+video_title,'wb') as f:
f.write(video_data)
print('下载完成...\n')
以上是单页面爬取
注意:
.content是是因为获得视频url得到的数据(图像,音频,视频)。
requests的请求返回的是一个对象
.text是文本数据
如何实行翻页
看着network,你往下翻,看数据包是否变化
这是参数变化
这里翻页的包的请求参数没有变化。
**这是相同的URL的地址,返回的数据不一样。**这里是没有变化,需要注意的点。
有些是会变化的。
所以构建for循环就行了
因为这个URL是没有变化的。
b站不可以,因为是有参数加密。
参考视频
https://www.bilibili.com/video/BV1Fy4y1D7XS
网页源代码有些东西有,这是静态页面的吗?
这是视频流数据
b站视频画面和音频数据是分开的,意思就是视频时无声的。
它是在playinfo找到baseurl中找到视频地址。
但是没有声音。
微博
这个类似于好看视频
只是实现单页面模式,但是里面post_form中的
需要自己调一次获得的视频个数,但是这个搞笑区效果不好,暂时不打算继续下去,但是代码已经成功实现能成功爬取视频,只是多页面等操作看后面搞不搞把。
跟好看视频是一样的模式
https://www.baomihua.com/funny
地址在这里面的link,然后点击之后跳转到另外一个页面然后还可以获得视频url地址。
然后就得到地址。
上面是post请求
https://www.bilibili.com/video/BV1Ub411B7aM?from=search&seid=739901640749625509
它前面得到Playid,的后面是后一个链接需要post的数据。
最后一个得到json得到mp4
第一次尝试:
实际运用到代理中出现的问题
目前快代理的高匿名代理可以使用了,
目标测试网址是百度
这貌似是静态页面,这个有视频的小栏的在class这个类里面
这个点击之后才出现下拉框
这个链接地址就是视频所在url。
完善
useragent应该使用动态的
点击之后这就是链接地址。
其实也就是源码中的点击之后获得源码中获得的url。他request的源代码到这一层就结束了。
脚本中的编码
https%3A%2F%2Ff.video.weibocdn.com%2FQ9fBi7UMlx07K3B0OMWI010412013yjx0E010.mp4%3Flabel%3Dmp4_hd%26template%3D480x720.25.0%26trans_finger%3Dd8257cc71422c9ad30fe69ce9523c87b%26ori%3D0%26ps%3D1EO8O2oFB1ePdo%26Expires%3D1612438106%26ssig%3Ds8dF79pY%252FR%26KID%3Dunistore%2Cvideo
数据保存在这里面但是经过编码的。
%2F是/
%3A是:
%3F是?
%3D是=
%26是&
%25是%
%2C是, (逗号)
.(点)还是不变
下划线没有变
所以这就涉及对Url进行解码:
所以我们接下来需要进行的是如何获得script里面对应的编码好的url。
参考b站那个代码
都是上面红框那一栏。
如何解析出来说一个json数据格式(他妈的)
第一次解析之后,json数据格式一看
最终得到里面的html,自己加上html封装一下,得到
这里前面的想法
html_data.text是前面requst.get返回的数据
# 下面的思路
找到对应的script下的标签,有不同script,但是发现视频那一栏的html在索引为2的那个script里面,然后去掉前后一些东西得到一个json字符串,使用Loads解析json最终得到里面的hml字符串。
html_data =html_data.text
# 正则表达式匹配
video_title= re.findall('<script charset="utf-8">FM.view\(([\d\D]*?)\)</script>',html_data) # 返回得是一个列表
if(len(video_title)>=3):
video_title = video_title[2]
with open('第一次得到正则.html','w',encoding='utf-8') as f:
# if(len(video_title)!=0):
f.write(video_title)
# 得到的是一个json格式的字符串
json_scipt_data = json.loads(video_title)
json_html_str= json_scipt_data['html']
# 得到是html字符串
# video\.weibocdn([\d\D]*?)unistore
# https://f.video.weibocdn.com 参数 =unistore,video
# 所以我们需要拼接一下然后转码,因为得到的字符串参数是没有编码的
else:
print('没有匹配成功')
基于上面,经过测试发现,我直接全局正则匹配对应的视频URL链接。还稳定
推荐正则表达式测试使用得软件:没有广告:RegexMatchTracerCr
re.findall('video\.weibocdn([\d\D]*?)unistore',contents)
结果又发现取得真正得url。
他前缀不一定一样,脑壳痛
那我们就先搞微博开头得,你正常解码一对比,发现
你解析得直接点击原来发现服务器给你禁止了。
换个ip,有效
提取标题
对于H3标签下,a和img数量不固定,但是还
开头,里面有个谁的微博视频那个标签目前发现是固定的。
正则表达式:
已经这个来划分。
list_title_s(.*?)的微博视频
然后我再删除非汉字(文本的内容)
一定要带着cookie走,如何usergent换他里面的,不然会返回东西,但不是你想要的。
这里写完了:
该py文件可以直接运行,只需要下载依赖库
因为我自己安装的是anaconda+python3.7
再加上里面安装的库
没有使用selemium这种操作,里面的文件只是当时的一个思路,但实际中未使用。
这是最原始的版本,能爬取视频
但是需要优化的是:
1:动态从csv中获取相同IP,即使用代理池,ip全部保存在Ip_pool.csv中
2:当过多访问ip导致被封时候,再动态获取ip
3:注意获得的视频地址和标题数目是否一样多
4:视频地址解析目前其实有问题,因为不一定都是https://f.video.weibocdn 开头的
4:保存该视频链接来源,这样打开数据就知道该视频哪里来的(这个暂时不需要,都写微博搞笑视频就行了)
5:对一些错误进行处理
6:进行实现多页面翻页
6:正则表达式需要优化
7:多线程
8:动态使用user-agent
9: 架构一点,多封装
对于Ip的csv文件的处理
# 第一点优化实现,顺序使用,如果该ip被屏蔽之后就依次调用第二个,这样就不会因为随机数重复使用csv中被屏蔽的ip
import pandas as pd
# 这里使用读取csv来获得ip,不用以下方式就注释掉,直接用上面的就可以
df = pd.read_csv("ip_pool.csv")
# # 这里直接变成数组格式
df_list=df.values.tolist()
# 我没有必要取随机数,如果这一个不行我直接取下一个
# 这个索引是从0开始
csv_ip_local = 0 # csv中用到第几个Ip了
proxies = {
# type :ip 行列定位
df_list[csv_ip_local][0]: df_list[csv_ip_local][1]
}
// 但这样会存在一个问题,因为从快代理的ip我以前使用过被微博禁了
思路:获取Ip的时候测试是否有效不仅经过`http://httpbin.org/get`,还经过微博网站试探一下,如果可以就加入csv里面。
出现这个问题
连续几个之后就不能用了。
我觉得是因为
对于WeiBo1.3.py
是对正则表达式的完全重构。针对
这里出现不可用的情况是因为有些视频也是别人搬运的,在别的网站上
WeiBo1.3.py
之前的都是只获得https://f.video.weibocdn.com :这种开头类型的,但是对于从秒拍视频这种搬运的https://n1cdn.miaopai.com/stream/
就无法获取,至于为什么获取的视频和得到的标题能一一对于,是因为你获得标题的正则表达式:
所以前面把外面视频网址去掉,视频标题把外面视频标题去掉,所以正好一一对应。
解决办法
把视频的栏目这一栏放到一个整体来读取
你会发现UG_list_v2 clearfix
是每个视频的标题的class。
所以得到的视频的标题:UG_list_v2 clearfix([\d\D]*?)视频
。然后再去解析。
遇见问题:
上面这是ip被封了。
优化:
1:ip和useragent都取随机数,如果一个ip重复读取更容易被封
2:被封的ip需不需要再删掉,全部ip被封在调用爬取匿名代理的函数(这个idea方法暂定)
1:useragent都取随机数
weibo1.4.py经常ip被封只能读取下一个
实现:
使用fake-useragent
pip install fake-useragent
2:ip取随机数
# 重新获得随机IP
def get_randon_ip():
if(list_ip_len):
csv_ip_local = random.randint(0,list_ip_len-1) # csv中用到第几个Ip了
else:
csv_ip_local=0
print('已经没有可用的IP地址了') # 后面可以在这里选择是否重新爬取IP形成代理池
new_proxies = {
# type :ip 行列定位
df_list[csv_ip_local][0]: df_list[csv_ip_local][1]
}
return new_proxies
目标:人人网登录
这样子就会直接跳转。
获取cookies(本来就已经存在cookie),这时候对于如何页面跳转能够一直保持登录状态。
记录登录状态。
这种效率不高
因为一个新的界面就会当前js,css样式表等.
这种效率比request低很多.
定位元素使用chropath插件.
对人人网测试使用父组件的div也可以.click
函数
遇见的一些错误
https://stackoverflow.com/questions/65755603/selenium-ssl-client-socket-impl-cc-handshake-failed