今日头条文章采集软件( 海量Python学习资料!目录需要的Python模块实现思路代码及运行结果)
优采云 发布时间: 2021-11-29 06:28今日头条文章采集软件(
海量Python学习资料!目录需要的Python模块实现思路代码及运行结果)
最近在今日头条文章的数据抓取过程中,发现获取视频地址比较复杂。在源码和浏览器的配合下找到了相应的解决方法,请记录下来。
点击此处获取海量Python学习资料!
目录实现思路代码和运行结果文本所需的Python模块
1.所需的 Python 模块
模块主要有requests(或者aiohttp),PyExecJS。
前者是请求文章的源码,后者是Python执行JS代码的依赖库,主要是生成视频地址
12
实现思路一. 需求主要是将原来文章中的视频和图片地址替换为本地存储地址,所以需要下载资源,在视频中通过抓包找到对应的视频地址分析。源码和相关接口响应中没有找到对应的视频地址参数。
通过文章源代码(HTML)浏览器渲染,发现video标签是后面生成的,而且video地址也存在,那么这个标签肯定是JS生成的,找到关键的JS标签脚本通过搜索
二. 解析地址对应的js,发现有生成视频标签的方法,推断有依次生成视频地址的方法,如下:
在这里可以很清楚我们想要的视频地址是从哪里来的,方法如下:
分析方法,我们发现有一个关键参数t,而在图2中,我们找到了方法e,填入了参数v。这让我想起了前面捕获中接口返回的结果对应的main_url。无功 u = o。data.video_list, h = u.video_1, v = h.main_url, 123三. 接口为:/video/urls /1/toutiao/mp4/v0201f800000bub4vq2vtt9a5oknnlp0?callback=tt__video__3e9q4q
在界面返回结果中:
同时该接口中的参数(v0201f800000bub4vq2vtt9a5oknnlp0)在源码中可以找到,可以通过规则匹配。
你可以大胆尝试。在生成视频地址的方法中添加 main_url 值。另外还需要加上JS最底层的几个参数,即: var c = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, - 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,- 1, -1, -1, -1, -1, -1 , 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, - 1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 , 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38 , 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1,- 1, -1, -1); 1
我用的是JS调试工具(方便调试,检查代码语法),其他方法也可以
结果是:
/ B 742fb26ade01b94ae81b46009d87380 / 5f9944fe /视频/ TOS / CN / TOS-CN-VE-31 / cb2c3a57a679486eba880ef014c36ca0 / A = 2011&BR = 1368&BT = 456&CR = 0&CS = 0&CV = 1&DR7 = 0&DS = 1&RCV = 1&*敏*感*词*=&石灰=&limetype = M29xcmR3eXQ3eDMzM2kzM0ApZmVkZjo5OGVkNzM6PDozaWdta2gyNnEvc19fLS01Li9zczIuLl41YTFjXi8yMTReYGM6Yw%3D %3D&vl=&vr=
地址是视频地址,所以证明上面的猜想是正确的,但是地址参数是时效性的,所以需要动态修改。您可以自己测试并重新生成它。
代码和运行结果(我用了不同的方法)
<p>async def get_page_source(url):
browser = None
page = None
try:
browser = await launch(
headless=True,
ignoreHTTPSErrors=True,
handleSIGINT=False,
handleSIGTERM=False,
handleSIGHUP=False,
defaultViewport=None,
args=['--disable-setuid-sandbox',
'--no-sandbox',
'--ignore-certificate-errors',
'--disable-gpu',
'--disable-gpu-sandbox',
'--start-maximized'
]
)
pages = await browser.pages()
page = pages[0]
# 是否启用JS,enabled设为False,则无渲染效果
await page.setJavaScriptEnabled(enabled=True)
await page.setViewport(viewport={'width': 1200, 'height': 800})
await page.evaluateOnNewDocument(
'() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }')
await page.evaluateOnNewDocument("() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [] }) }")
await page.evaluateOnNewDocument(
"() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['zh-CN','zh] }) }")
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36')
await page.goto(url, {'timeout': 5000, 'waitUntil': 'load'})
page_source = await page.content()
return page_source
except Exception as e:
# app_logger.error('账号:%s, 登录错误:%s' % (username, e))
print(e)
return -1
finally:
if page is not None:
# await page.waitFor(1000)
await page.close()
if browser is not None:
await browser.close()
async def get_data(url, continue_number=0):
"""解析文章源码,提取视频,文字,图片等信息"""
try:
page_source = await get_page_source(url)
# 视频处理,及视频封面
video_message_id_ = re.findall('tt-videoid="(.*?)"', page_source)
video_cover_ = re.findall('tt-poster="(.*?)"', page_source)
if len(video_message_id_) > 0 and len(video_cover_) > 0:
video_message_id = video_message_id_[0]
video_url = await get_video_url_id(video_message_id, url)
video_cover = await download_video_cover(video_cover_[0], url)
except Exception as e:
if continue_number < continue_num:
print(e)
# app_logger.error('function get_data error: %s' % e)
continue_number += 1
video_address = await get_data(url, continue_number)
return video_address
else:
# app_logger.error('function get_data : %s exceed maximum retry' % url)
return -1
async def get_video_url_id(video_id, article_url, continue_number=0):
"""解析视频main_url"""
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/83.0.4103.116 Safari/537.36'}
data_url = 'https://i.snssdk.com/video/urls/1/toutiao/mp4/{}'.format(video_id)
try:
async with aiohttp.ClientSession(connector=TCPConnector(verify_ssl=False), timeout=timeout) as session:
async with session.get(data_url, headers=header) as resp:
response = await resp.json()
if response['message'].strip() == "success":
data = response['data']['video_list']
keys = data.keys()
if 'video_3' in keys:
main_url = data['video_3']['main_url']
video_url = await get_video_url(main_url)
video_url_oss = await download_video(video_url, article_url)
return video_url_oss
elif 'video_3' not in keys and 'video_2' in keys:
main_url = data['video_3']['main_url']
video_url = await get_video_url(main_url)
video_url_oss = await download_video(video_url, article_url)
return video_url_oss
else:
main_url = data['video_3']['main_url']
video_url = await get_video_url(main_url)
video_url_oss = await download_video(video_url, article_url)
return video_url_oss
except Exception as e:
if continue_number < continue_num:
print(e)
# app_logger.error('function get_data error: %s' % e)
continue_number += 1
video_address = await get_data(url, continue_number)
return video_address
else:
# app_logger.error('function get_data : %s exceed maximum retry' % url)
return -1
async def get_video_url(main_url, continue_number=0):
"""获取视频地址,js执行"""
try:
tt = """var c = new Array( - 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
function e(t) {
var e, o, i, r, n, a, s;
for (a = t.length, n = 0, s = ""; a > n;) {
do e = c[255 & t.charCodeAt(n++)];
while (a > n && -1 == e);
if ( - 1 == e) break;
do o = c[255 & t.charCodeAt(n++)];
while (a > n && -1 == o);
if ( - 1 == o) break;
s += String.fromCharCode(e > 4);
do {
if (i = 255 & t.charCodeAt(n++), 61 == i) return s;
i = c[i]
} while ( a > n && - 1 == i );
if ( - 1 == i) break;
s += String.fromCharCode((15 & o) > 2);
do {
if (r = 255 & t.charCodeAt(n++), 61 == r) return s;
r = c[r]
} while ( a > n && - 1 == r );
if ( - 1 == r) break;
s += String.fromCharCode((3 & i)