百度APP爬蟲
阿新 • • 發佈:2018-11-11
1.抓包
訪問一個頻道,Charles抓包,找到真實連線,一般返回json資料和網頁中資料對應為真實連線
請求方式為post,所以要新增請求頭和表單資料,由於在charles環境下,所以要新增charles的代理ip和認證檔案,然後進行測試,訪問成功。
對不同的頻道分別經過charles抓包,發現請求的連結都是一樣的,只是更換了表單中tab_id屬性來對應不同的頻道,所以建立一個儲存tab_id和頻道名的字典,更換時從tab_id字典中取值,來實現不同頻道的訪問
2.封ip測試
一直訪問並沒有被封,所以就放開了採吧
3.概覽頁
一般概覽頁的資料庫中存放文章的連結,但是這個百度APP返回資料中含有所有欄位,所以將返回的資料全部存放到資料庫中。
4.細覽頁
讀取概覽頁資料庫中的資料,通過正則解析出各個欄位,去除無效資訊,欄位加密存放到資料庫中
注:charles代理ip自行設定;url只提供一個樣子,自行抓取;資料庫自行設定;認證檔案自行設定;表單資料自行抓取;資料解析模組需要什麼自己就解析什麼,這裡不提供了;處理上還不是很完美,自行修改;
gailanye.py
1 import requests 2 import re 3 import time 4 import pymysql 5 6 7 classBD(object): 8 def __init__(self): 9 self.url = 'https://mbd.baidu.com/searchbox?-此處省略-7ig' 10 self.form = { 11 'data': '''此處省略。。。 12 13 ''' 14 15 } 16 self.proxy = { 17 'https': 'https://此處省略' 18} 19 self.channel = { 20 '1': '推薦', 21 '3': '娛樂', 22 '4': '體育', 23 '5': '時尚', 24 '6': '國際', 25 '8': '熱點', 26 '12': '汽車', 27 '13': '軍事', 28 '14': '科技', 29 '15': '財經', 30 '16': '遊戲', 31 '17': '女人', 32 '18': '歷史', 33 '28': '搞笑', 34 '35': '情感', 35 '34': '美食', 36 '41': '居家', 37 '42': '政務', 38 '43': '旅遊', 39 '44': '闢謠', 40 '51': '健康', 41 '54': '萌寵', 42 '72': '新華社', 43 '75': '虎撲', 44 '81': '澎湃新聞', 45 '85': '人民日報', 46 '106': '36氪', 47 '88': '虎嗅', 48 '309999289': '上海', 49 '309999257': '廣州', 50 '309999340': '深圳', 51 '309999332': '天津', 52 '309999179': '杭州', 53 '309999315': '南京', 54 '309999218': '武漢', 55 '109999131': '北京', 56 } 57 58 def modify_tab_id(self, tab_id): 59 # 修改表單中的tab_id 60 self.form['data'] = re.sub('"tab_id": "(\d+)"', '"tab_id": "{}"'.format(tab_id), self.form['data']) 61 # self.form['data'] = re.sub('"last_update_time": (\d+),', '"last_update_time": {}000,'.format(int(time.time())), self.form['data']) 62 return self.form['data'] 63 64 def get_data(self): 65 # 獲得頻道和內容 66 list_d = [] 67 for data in self.channel: 68 data_channel = [] 69 print('='*20) 70 print(data) 71 self.form['data'] = self.modify_tab_id(data) 72 response = requests.post(self.url, data=self.form, proxies=self.proxy, verify='*.pem') 73 datas = response.text 74 channel = self.channel[data] 75 data_channel = [channel, datas] 76 print(data_channel) 77 list_d.append(data_channel) 78 return list_d 79 80 def save_data(self, list_d): 81 # 寫入資料庫 82 host = '127.0.0.1' 83 db = 'bd' 84 user = 'root' 85 psd = '123456' 86 charset = 'utf8' 87 88 con = pymysql.connect(host=host, db=db, user=user, passwd=psd, charset=charset) 89 90 cur = con.cursor() 91 92 for i in list_d: 93 print(i) 94 sql = ( 95 "insert into gly(此處省略)" 96 "values(此處省略)") 97 list_m = [i[0], i[1]] # i[0]為頻道名 i[1]為資料 98 try: 99 cur.execute(sql, list_m) 100 print('insert success') 101 except Exception as e: 102 print('insert error', e) 103 con.rollback() 104 else: 105 con.commit() 106 cur.close() 107 con.close() 108 109 110 if __name__ == '__main__': 111 bd = BD() 112 list_d = bd.get_data() 113 bd.save_data(list_d)
xilanye.py
1 import pymysql 2 import json 3 import time 4 import hashlib 5 import requests 6 from lxml import etree 7 import re 8 9 10 # 娛樂頻道先刪除掉 11 # 體育頻道有導航欄目前還無法獲取data,先過濾掉 12 13 14 class XLY(object): 15 def __init__(self): 16 self.no_results_channel = [] # 儲存沒有資料的頻道 17 self.proxy = { 18 'https': '....' 19 } 20 self.sum_data = 0 21 22 def get_data(self): 23 host = '127.0.0.1' 24 db = 'bd' 25 user = 'root' 26 pwd = '123456' 27 charset = 'utf8' 28 con = pymysql.connect(host=host, db=db, user=user, passwd=pwd, charset=charset) 29 30 datas = [] 31 cur = con.cursor() 32 sql = 'select * from gly' 33 try: 34 cur.execute(sql) 35 results = cur.fetchall() 36 i = 0 37 for result in results: 38 i += 1 39 data = [] 40 # 讀出來是元組型別,轉化為列表返回 41 result = list(result) 42 if '{"100":[]}' in result[1]: 43 self.no_results_channel.append(result[0]) 44 print('no results channel:', result[0]) 45 elif 'navigatorItems' in result[1]: 46 print('有導航欄的頻道,還沒有處理') 47 else: 48 data = [result[0], result[1]] 49 datas.append(data) 50 print('get_data') 51 print('=' * 20, i) 52 # if i == 5: 53 # break 54 except Exception as e: 55 print('error', e) 56 con.rollback() 57 else: 58 con.commit() 59 return datas 60 61 def parse_data(self, datas): 62 items = [] 63 for data in datas: 64 channel = data[0] 65 channel_data = data[1] 66 channel_data = json.loads(channel_data) 67 channel_data = channel_data['data']['100']['itemlist']['items'] 68 69 for text in channel_data: 70 print('='*20) 71 item = {} 72 try: 73 mode = text['data']['mode'] 74 except: 75 mode = '' 76 print('mode not found') 77 # 根據mode判斷是否為文章,過濾掉圖集廣告 78 if mode == 'text': 79 此處省略 87 88 m1 = hashlib.md5() 89 m1.update(item['urlname'].encode("utf8")) 90 item['hkey'] = m1.hexdigest() 91 92 try: 93 item['comments'] = text['data']['comment_num'][:-2] 94 except: 95 item['comments'] = '' 96 print('no comment_num') 97 98 # 解析content 99 content, url_time = self.parse_content(item['urlname']) 100 101 102 print(item) 103 self.save_data(item) 104 if item != {}: 105 items.append(item) 106 return items 107 108 def parse_content(self, url): 109 # 根據每一篇文章獲取content, url_time 110 response = requests.get(url, proxies=self.proxy, verify='此處省略.pem') 111 text = response.text 112 element = etree.HTML(text) 113 contents = element.xpath('//p[@class="contentText contentSize contentPadding"]//text()') 114 url_time = element.xpath('//div[@class="infoSet"]//text()') 115 try: 116 if '17-' in url_time: 117 url_time = re.sub('17', '2018', url_time) 118 print(url_time) 119 else: 120 url_time = '2018-' + str(url_time[1]) 121 except: 122 url_time = '' 123 if not contents: 124 contents = '' 125 else: 126 contents = ''.join(contents) 127 return contents, url_time 128 129 def save_data(self, item): 130 host = '127.0.0.1' 131 db = 'bd' 132 user = 'root' 133 pwd = '123456' 134 charset = 'utf8' 135 136 con = pymysql.connect(host=host, db=db, user=user, passwd=pwd, charset=charset) 137 cur = con.cursor() 138 sql = 'insert into xly(此處省略)' \ 139 'values(此處省略)' 140 list = [此處省略] 142 try: 143 cur.execute(sql, list) 144 print('insert success') 145 self.sum_data += 1 146 print('成功插入資料庫第{}條'.format(self.sum_data)) 147 except Exception as e: 148 print('error~~', e) 149 con.rollback() 150 else: 151 con.commit() 152 # cur.execute(sql, list) 153 cur.close() 154 con.close() 155 156 157 if __name__ == '__main__': 158 xly = XLY() 159 datas = xly.get_data() 160 items = xly.parse_data(datas)