1. 程式人生 > >百度APP爬蟲

百度APP爬蟲

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 class
BD(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)