這兩天知識星球上有球友要求布置一個抓取得到App數(shù)據(jù)的作業(yè),于是我二話不說就擼了一把.
效果圖如下



我們以前都是在網(wǎng)頁上抓取數(shù)據(jù),很少在手機App中抓取數(shù)據(jù),那如何在抓取手機App中的數(shù)據(jù)呢?一般我們都是使用抓包工具來抓取數(shù)據(jù).
常用的抓包工具有Fiddles
與Charles
,以及其它今天我這里主要說說Charles
使用,相比于Fiddles
,Charles
功能更強大,而且更容易使用. 所以一般抓包我推薦使用Charles
下載與安裝Charles
下載并安裝Charles 再去破解Charles,這里附上文章教程,我就不多說啥了
https://www.cnblogs.com/rrl92/p/7928770.html
注意事項:
如果獲取到的數(shù)據(jù)是亂碼,你要設(shè)置一下連接SSL證書 在Charles中 菜單欄==>proxy==>SSL Proxying Settings ==>添加443,如上圖所示. 然后當(dāng)你在真正抓取數(shù)據(jù)的時候,記得把這個關(guān)掉,以免取不到數(shù)據(jù)

使用Charles
這里我直接放兩張圖讓大家使用看看就明白了


我們一起來分析項目.
打開Charles 然后打開手機,得到App,進(jìn)入邏輯思維欄目. 多次刷新App, 在Charles中 Structure中有變黃的一項就是我們當(dāng)前的請求,
查看右邊的Overview欄目,這里我們很容易發(fā)現(xiàn)我們的請求路徑,狀態(tài),以及請求方式
點擊Contents欄目,上面是Requests區(qū)域,下面是Response區(qū)域. 可以看到上面的Headers 這里就是我們實際寫代碼時候要用到的Headers,** 注意構(gòu)造Heaers時,不要出現(xiàn)了空格,我剛剛就犯了這個錯誤**
再看Form欄目,這里是我們構(gòu)造Post請求需要的一些參數(shù),我們在請求的時候,注意這里面的數(shù)據(jù)變化,來找出數(shù)據(jù)請求的規(guī)律.
這里我找到的數(shù)據(jù)請求規(guī)律就是通過改變時間戳來獲取數(shù)據(jù).
我打算把獲取的數(shù)據(jù)存入到execl中,并下載相關(guān)的音頻.
我們就開始來寫代碼. 定義一個dedao
類, 定義了三個方法 request_data()
parse_data()
download_mp3()
代碼結(jié)構(gòu)如下: 這里我強調(diào)一下,一定要先有大致的思路再去寫代碼,我這里定義了三個方法,我心中已經(jīng)知道具體流程了.

另外要注意一下,我能之前說了得到是通過時間戳來去請求下一頁數(shù)據(jù),那什么時候把數(shù)據(jù)請求完了呢,以及如何去請求下一頁數(shù)據(jù), 如果時間戳與我當(dāng)前存的時間戳不一致,說明還有下一頁數(shù)據(jù),否則就是數(shù)據(jù)請求完了,具體代碼如下:
# 這里有點遞歸的意味
max_id = datas[-1]['publish_time_stamp']
if self.max_id != max_id:
self.max_id = max_id
self.request_data()
else:
print('數(shù)據(jù)抓取完畢!')
完整代碼:
import requests
import time
import json
from dedao.ExeclUtils import ExeclUtils
import os
class dedao(object):
def __init__(self):
# self.rows_title = [u'招聘標(biāo)題', u'公司名稱', u'公司地址', u'待遇', u'發(fā)布日期', u'招聘鏈接', u'招聘要求描述']
# sheet_name = u'51job_Python招聘'
self.rows_title = [u'來源目錄', u'標(biāo)題', u'圖片', u'分享標(biāo)題', u'mp3地址', u'音頻時長', u'文件大小']
sheet_name = u'邏輯思維音頻'
return_execl = ExeclUtils.create_execl(sheet_name, self.rows_title)
self.execl_f = return_execl[0]
self.sheet_table = return_execl[1]
self.audio_info = [] # 存放每一條數(shù)據(jù)中的各元素,
self.count = 0 # 數(shù)據(jù)插入從1開始的
self.base_url = 'https://entree./acropolis/v1/audio/listall'
self.max_id = 0
self.headers = {
'Host': 'entree.',
'X-OS': 'iOS',
'X-NET': 'wifi',
'Accept': '*/*',
'X-Nonce': '779b79d1d51d43fa',
'Accept-Encoding': 'br, gzip, deflate',
# 'Content-Length': ' 67',
'X-TARGET': 'main',
'User-Agent': '%E5%BE%97%E5%88%B0/4.0.13 CFNetwork/901.1 Darwin/17.6.0',
'X-CHIL': 'appstore',
'Cookie ': 'acw_tc=AQAAAC0YfiuHegUAxkvoZRLraUMQyRfH; aliyungf_tc=AQAAAKwCD1dINAUAxkvoZTppW+jezS/9',
'X-UID': '34556154',
'X-AV ': '4.0.0',
'X-SEID ': '',
'X-SCR ': '1242*2208',
'X-DT': 'phone',
'X-S': '91a46b7a31ffc7a2',
'X-Sign': 'ZTBiZjQyNTI1OTU2MTgwZjYwMWRhMjc5ZjhmMGRlNGI=',
'Accept-Language': 'zh-cn',
'X-D': 'ca3c83fca6e84a2d869f95829964ebb8',
'X-THUMB': 'l',
'X-T': 'json',
'X-Timestamp': '1528195376',
'X-TS': '1528195376',
'X-U': '34556154',
'X-App-Key': 'ios-4.0.0',
'X-OV': '11.4',
'Connection': 'keep-alive',
'X-ADV': '1',
'Content-Type': 'application/x-www-form-urlencoded',
'X-V': '2',
'X-IS_JAILBREAK ': 'NO',
'X-DV': 'iPhone10,2',
}
def request_data(self):
try:
data = {
'max_id': self.max_id,
'since_id': 0,
'column_id': 2,
'count': 20,
'order': 1,
'section': 0
}
response = requests.post(self.base_url, headers=self.headers, data=data)
if 200 == response.status_code:
self.parse_data(response)
except Exception as e:
print(e)
time.sleep(2)
pass
def parse_data(self, response):
dict_json = json.loads(response.text)
datas = dict_json['c']['list'] # 這里取得數(shù)據(jù)列表
# print(datas)
for data in datas:
source_name = data['audio_detail']['source_name']
title = data['audio_detail']['title']
icon = data['audio_detail']['icon']
share_title = data['audio_detail']['share_title']
mp3_url = data['audio_detail']['mp3_play_url']
duction = str(data['audio_detail']['duration']) + '秒'
size = data['audio_detail']['size'] / (1000 * 1000)
size = '%.2fM' % size
self.download_mp3(mp3_url)
self.audio_info.append(source_name)
self.audio_info.append(title)
self.audio_info.append(icon)
self.audio_info.append(share_title)
self.audio_info.append(mp3_url)
self.audio_info.append(duction)
self.audio_info.append(size)
self.count = self.count + 1
ExeclUtils.write_execl(self.execl_f, self.sheet_table, self.count, self.audio_info, u'邏輯思維音頻.xlsx')
print('采集了{(lán)}條數(shù)據(jù)'.format(self.count))
# 清空集合,為再次存放數(shù)據(jù)做準(zhǔn)備
self.audio_info = []
time.sleep(3) # 不要請求太快, 小心查水表
max_id = datas[-1]['publish_time_stamp']
if self.max_id != max_id:
self.max_id = max_id
self.request_data()
else:
print('數(shù)據(jù)抓取完畢!')
pass
def download_mp3(self, mp3_url):
try:
# 補全文件目錄
mp3_path = u'D:/store/mp3/{}'.format(mp3_url.split('/')[-1])
print(mp3_path)
# 判斷文件是否存在。
if not os.path.exists(mp3_path):
# 注意這里是寫入文件,要用二進(jìn)制格式寫入。
with open(mp3_path, 'wb') as f:
f.write(requests.get(mp3_url).content)
except Exception as e:
print(e)
if __name__ == '__main__':
d = dedao()
d.request_data()