http://blog.csdn.net/u011475134/article/details/70198533 原出處 在上一篇文章《使用python-aiohttp爬取網易雲音樂》中,我們給自己的微信公眾號添加了線上點歌的功能,這次我們再增加一個新聞瀏覽的功能。由於我平時瀏覽新聞用的是今日頭條, ...
http://blog.csdn.net/u011475134/article/details/70198533 原出處
在上一篇文章《使用python-aiohttp爬取網易雲音樂》中,我們給自己的微信公眾號添加了線上點歌的功能,這次我們再增加一個新聞瀏覽的功能。由於我平時瀏覽新聞用的是今日頭條,所以在這裡就想通過爬取今日頭條來獲取新聞。不過遺憾的是,這一次我在網上沒有找到滿意的方法,所以還是自己動手吧。
打開抓包軟體Fiddler並設置Filters。
打開今日頭條網頁,選擇熱點。
url:http://www.toutiao.com/ch/news_hot/
在Fiddler中找到與上面新聞對應的json數據與url,由於json數據太多,這裡只給出部分。
{ "has_more": false, "message": "success", "data": [ { "chinese_tag": "體育", "media_avatar_url": "http://p3.pstatp.com/large/3538/9145332", "is_feed_ad": false, "tag_url": "news_sports", "title": "中國足協想搬出北京五環,原來是相中了這塊風水寶地", "single_mode": true, "middle_mode": true, "abstract": "中國足協搬家的傳說,很可能將水落石出。而且,此前的傳說其實很靠譜,中國足協確實有意要從目前位於北京東城區夕照寺街的東玖大廈,搬到京城五環路以外。南海子雖然在北京五環外,但是緊鄰南五環,距離位於體育館路的國家體育總局也不過19公裡。", "tag": "news_sports", "behot_time": 1492391171, "source_url": "/group/6409606379224957186/", "source": "長安街知事", "more_mode": false, "article_genre": "article", "image_url": "http://p3.pstatp.com/list/190x124/1bf4000b11da52a33c32", "has_gallery": false, "group_source": 2, "comments_count": 28, "group_id": "6409606379224957186", "media_url": "/c/user/4327876576/" },{},{},{},{},{},{} ], "next": { "max_behot_time": 1492391156 } }
可以看到,在json數據中的data是一個包含新聞的列表,其中的title是新聞的標題,abstract是新聞的摘要,source_url是新聞的鏈接,image_url是新聞圖片的鏈接,這些都是我們需要的。
http://www.toutiao.com/api/pc/feed/?category=news_hot&utm_source=toutiao&widen=1&max_behot_time=0&max_behot_time_tmp=0&tadrequire=true&as=A135888F14A1507&cp=58F4A1A500177E1
參數 | 取值 | 說明 |
---|---|---|
category | news_hot | 類型,定值 |
utm_source | toutiao | 定值 |
widen | 1 | 定值 |
max_behot_time | 0 | 偏移量(預設為0) |
max_behot_time_tmp | 0 | 與max_behot_time相等 |
tadrequire | true | 定值 |
as | A135888F14A1507 | 未知 |
cp | 58F4A1A500177E1 | 未知 |
通過多次觀察發現,max_behot_time類似偏移量,點擊熱點時,取值為零,下拉網頁時,取值為上一個josn數據中的next[max_behot_time],由於點擊熱點就可以刷新新聞,所以讓max_behot_time等於固定值0就好。
as和cp每次都會改變,但沒有找到規律,推測應該是每次請求時,按照一定規律生成的數據,於是查看網頁源碼,很明顯,下麵這段代碼就是用來產生as和cp的,從代碼中可以看到,as和cp相當於一個時間戳,我們可以仿照這段代碼用python來生成as和cp。
e.getHoney = function() { var t = Math.floor((new Date).getTime() / 1e3), e = t.toString(16).toUpperCase(), i = md5(t).toString().toUpperCase(); if (8 != e.length) return { as: "479BB4B7254C150", cp: "7E0AC8874BB0985" }; for (var n = i.slice(0, 5), a = i.slice( - 5), s = "", o = 0; 5 > o; o++) s += n[o] + e[o]; for (var r = "", c = 0; 5 > c; c++) r += e[c + 3] + a[c]; return { as: "A1" + s + e.slice( - 3), cp: e.slice(0, 3) + r + "E1" } }
新建文件toutiao3.py,代碼如下:
1 import asyncio 2 from aiohttp import ClientSession 3 import time 4 import math 5 import hashlib 6 7 __NEWS_NUM = 1 # hu 返回的最大新聞數 8 9 def getASCP(): 10 t = int(math.floor(time.time())) 11 e = hex(t).upper()[2:] 12 m = hashlib.md5() 13 m.update(str(t).encode(encoding='utf-8')) 14 i = m.hexdigest().upper() 15 16 if len(e) != 8: 17 AS = '479BB4B7254C150' 18 CP = '7E0AC8874BB0985' 19 return AS,CP 20 21 n = i[0:5] 22 a = i[-5:] 23 s = '' 24 r = '' 25 for o in range(5): 26 s += n[o] + e[o] 27 r += e[o + 3] + a[o] 28 29 AS = 'A1' + s + e[-3:] 30 CP = e[0:3] + r + 'E1' 31 return AS,CP 32 33 async def __fetch(url,data,loop): 34 try: 35 async with ClientSession(loop=loop) as session: 36 # hu 發送GET請求,params為GET請求參數,字典類型 37 async with session.get(url, params=data,timeout=5) as response: 38 # hu 以json格式讀取響應的body並返回字典類型 39 return await response.json() 40 except Exception as ex: 41 print('__fetch:%s' % ex) 42 43 async def getNewsInfo(loop): 44 global __NEWS_NUM 45 AS,CP = getASCP() 46 urlTouTiao = 'http://www.toutiao.com' 47 urlNews = 'http://www.toutiao.com/api/pc/feed/' 48 dataNew = {'category': 'news_hot', 49 'utm_source': 'toutiao', 50 'widen': '1', 51 'max_behot_time': '0', 52 'max_behot_time_tmp':'0', 53 'tadrequire':'true', 54 'as':AS, 55 'cp':CP} 56 result = None 57 try: 58 task = asyncio.ensure_future(__fetch(urlNews, dataNew,loop),loop=loop) 59 taskDone = await asyncio.wait_for(task,timeout=5) 60 if 'message' not in taskDone or taskDone['message'] != 'success': 61 return result 62 63 result = {'max_behot_time':taskDone['next']['max_behot_time'], 64 'news':[]} 65 66 for news_hot in taskDone['data']: 67 news = {'Title': None, 68 'Description': None, 69 'PicUrl': None, 70 'Url': None} 71 # hu 去掉廣告 72 if news_hot['is_feed_ad']: 73 continue 74 news['Title'] = news_hot['title'] 75 if 'abstract' in news_hot: 76 news['Description'] = news_hot['abstract'] 77 else: 78 news['Description'] = '' 79 if 'image_url' in news_hot: 80 news['PicUrl'] = news_hot['image_url'] 81 else: 82 news['PicUrl'] = '' 83 news['Url'] = urlTouTiao + news_hot['source_url'] 84 result['news'].append(news) 85 if len(result['news']) == __NEWS_NUM: 86 break 87 # hu 把有圖片的新聞放到前面 88 result['news'].sort(key=lambda obj: obj.get('PicUrl'), reverse=True) 89 except Exception as ex: 90 print('getNewsInfo:%s' % ex) 91 return result 92 93 def __main(): 94 loop = asyncio.get_event_loop() 95 for ii in range(2): 96 task = asyncio.ensure_future(getNewsInfo(loop),loop=loop) 97 taskDone = loop.run_until_complete(task) 98 print('第%d次:' % ii) 99 for res in taskDone['news']: 100 print(res) 101 loop.close() 102 103 if __name__ == '__main__': 104 __main()
返回值:
第0次:
{'Title': '長沙現微型古籍 疑是明清科舉作弊用書', 'Description': '', 'PicUrl': 'http://p3.pstatp.com/list/190x124/1bbf000b36c2b4f07ca0', 'Url': 'http://www.toutiao.com/group/6409737414201721090/'}
第1次:
{'Title': '長沙現微型古籍 疑是明清科舉作弊用書', 'Description': '', 'PicUrl': 'http://p3.pstatp.com/list/190x124/1bbf000b36c2b4f07ca0', 'Url': 'http://www.toutiao.com/group/6409737414201721090/'}
結果每次獲取的新聞都是一樣的,通過Fiddler多次觀察,發現新聞的刷新和Cookie中的tt_webid有關,當該參數不存在時,則返回預設新聞與tt_webid,所以我們只要取出響應中的tt_webid,併在發送請求時給tt_webid賦值就好。
將toutiao3.py文件做如下修改:
1 #### hu 增加代碼 ###### 2 __cookie = None 3 ###################### 4 5 async def __fetch(url,data,loop): 6 global __cookie 7 try: 8 async with ClientSession(cookies=__cookie,loop=loop) as session: 9 async with session.get(url, params=data,timeout=5) as response: 10 ########################### hu 增加代碼 ############################## 11 if response.cookies and 'tt_webid' in response.cookies: 12 __cookie = {'tt_webid':response.cookies['tt_webid'].value} 13 ##################################################################### 14 return await response.json() 15 except Exception as ex: 16 print('__fetch:%s' % ex)
返回值:
第0次:
{'Title': '長沙現微型古籍 疑是明清科舉作弊用書', 'Description': '', 'PicUrl': 'http://p3.pstatp.com/list/190x124/1bbf000b36c2b4f07ca0', 'Url': 'http://www.toutiao.com/group/6409737414201721090/'}
第1次:
{'Title': '陳羽凡設立投資13家公司 3家被吊銷營業執照', 'Description': '[海峽都市報-海峽網](原標題:陳羽凡商業版圖冰火兩極)4月16日,歌手陳羽凡率先發聲,通過視頻正式澄清已與白百何協議離婚,並表示將無限期退出娛樂圈。一時之間,業內外開始對陳羽凡退出娛樂圈以後將何去何從進行諸多揣測。', 'PicUrl': 'http://p1.pstatp.com/list/190x124/1bbd000c3eef588ea140', 'Url': 'http://www.toutiao.com/group/6409610618823590146/'}
可以看到兩次返回的新聞不一樣。關於asyncio模塊的基本概念可參考《使用python-aiohttp搭建微信公眾平臺》,這裡就不一一註釋了。至於怎麼將今日頭條的功能添加到我們的微信公眾號,可以參考《使用python-aiohttp爬取網易雲音樂》,這裡就不貼代碼了。