Python 抓取电视猫官网数据制作 EPG (一)

电视节目指南或者说节目预告即EPG功能还是很实用的,比如 Perfect Player 内置解析标准格式的 EPG 文件,只要填入有效的 EPG 服务器地址就可以享受节目预告带来的便利,还有典型的“超级直播”,都是被IPTV爱好者津津乐道的功能。

电视猫网站的EPG数据还是比较全面的。
1. 首先是直接用 Chrome 打开 tvmao.com 网站抓包。发现网页地址名称很固定很有规律,基本上都是类似这样的:

  link = "https://www.tvmao.com"
  sublink = "/program/CCTV-CCTV2-w1.html"

其中的 w1 就是周一、二、三、四类推。
直接开干。(先附上代码片段)

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0',
            'Connection' : 'keep-alive', 'Cache-Control': 'no-cache'}
website = '%s%s' % (link, sublink)
r = requests.get(website, headers= headers)
 
soup = BeautifulSoup(r.text, 'lxml')
 
# 获取节目列表    
list_program_div = soup.find(name='div',attrs={"class":"pgmain"}).find_all(name='li'); #,attrs={"class":"over_hide"});
print(list_program_div);

很遗憾的是,打印出来一看,只有上午的节目。

2. 分析 Chrome 抓到的包,发现 午间节目及晚间节目是在 /api/pg?p=xxxx 接口获取的,后面带了一长串看起来就是 base64 的数据。
没办法 ,人家网站制定好的规则,我们只有按照他们的规则来做。
页面加载后,自动获取节目信息, 首先想到的是:

$(function() {
}

外加api/pg 路径, 在html 和 js 文件里搜索api ,成功在html里面找到。

eval(function(p,a,c,k,e,r){e=function(c){return c.toString(a)};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c][/c]||e(c);
k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};
while(c--)if(k[c][/c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c][/c]);return p}
('$(2(){3 b="4";3 d=c.d("a",b);$.5("/g/7",{8:d},2(a){9(a[0]==1){$("#e").f(a[1])}},"6")});
',17,17,'||function|var|src|get|json|pg|p|if|||A||noon|after|api'.split('|'),0,{}))

eval() 是 js 的函数,这里这串乱七八糟完全看不懂的代码是 js 加密后的代码,复制这段代码到 js eval 加解密的网站里(如果很倒霉解不出来,就换一个网站继续试),最终解出来的代码是这样的,这样就和链接的响应数据对上了,

$(function() {
    var b = "src";
    var d = A.d("a", b);
    $.get("/api/pg", {
        p: d
    },
    function(a) {
        if (a[0] == 1) {
            $("#noon").after(a[1])
        }
    },
    "json")
});

豁然开朗!同样的 A.d 也是要类似的方法解密后才能找到,在 base_20180615.js 文件里。

3. 分析 js 代码, 找到链接后面字符串的含义。
稍微了解点 js 的都可以看出来,A.d 在 html 里面第一个 form 里找 3 个字符串, 然后 base64 解码一下。

html 源码里面是这样的:

<form method="get" action="/query.jsp" name="QF" id="searchform"
     q="48E6E87B37B8AFF9411D08167090AE8F81EF1F78DAB16FD358C1949466"
     a="6F70099FF4CC2A471209EB6C01E35B8CFF"  > 
     <input style="vertical-align: middle;" type="text" id="key" name="keys" 
        class="topic_search_input ed ui-autocomplete-input font12" title="节目、电视剧、电影、明星一起搜!" 
        autocomplete="off" maxlength="40" size="40" role="textbox" aria-autocomplete="list" aria-haspopup="true" /> 
     <input type="hidden" name="ed" /> 
     <button type="submit" class="topic_button_blue" style="vertical-align: middle;" value="猫一把" 
     id="83FBAF3ED46521143DEB070A057D51F3D2832FC045">猫一下</button> 
    </form> 

python 代码是这样的,(只针对当前的网页,)我简化了一下:

	
list_first_form = soup.find(name='form');
print(list_first_form);
print(list_first_form["a"]);
print(list_first_form["q"]);
print(list_first_form.button["id"]);
 
def sub_req(a, q, id):
 
	_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		
	str1 = "|"+q;
	v = base64.b64encode(str1.encode('utf-8'));
	
	str2 = id+"|"+a;
	w = base64.b64encode(str2.encode('utf-8'));
	
	str3 = time.strftime("%w");
	wday = (7 if(int(str3) == 0) else int(str3));
	//print(wday);
	F = _keyStr[wday*wday];
		
	return (F+str(w,'utf-8')+str(v,'utf-8'));
	
sublink = "/api/pg?p="+sub_req(list_first_form["a"], list_first_form["q"], list_first_form.button["id"]);

黑鸟博客:www.guihet.com
到这里 ,我们可以正确的拼出链接! 并获取到剩下的节目列表。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

  1. 老死机 老死机 说道:

    博主,能不能教一教,pp怎么播放带referer限制的源?怎么播放加密的源?

    1. 黑鸟君 说道:

      这么骚的操作,真不会..

      1. 老死机 老死机 说道:

        这套台湾源你知道出自哪个app或网站吗?
        http://210.201.54.101/gtlive/xxxxxx/chunklist_w277913547.m3u8?st=1545558776690&token=M2U4NjFlMmRkM2JhNTZkNGJlN2M5YzYyYjJkZDRjYjYzM2RhOGRjZA%3D%3D
        我看星火直播也代理这套源,想自己也写一个

        1. 黑鸟君 说道:

          不知道..

  2. fy789 说道:

    太深奥了,不怎么懂 :razz: :razz: :razz:

  3. 楚狂人 说道:

    感谢博主的技术文章分享 :smile: