Python技能共建】動態渲染頁面爬取 R13

      網友投稿 759 2022-05-29

      Python 動態渲染頁面爬取

      動態渲染頁面爬取最常見的就是面向接口的爬蟲,在采集過程中需要首先分析出其接口地址,本文將帶來 2 個基于接口的爬蟲。

      怎么用

      目標站點【一派話題廣場】分析

      本篇博客的第一個采集目標站點是:https://Base64加密站點/matrix/pods,少數派網站的一個子級欄目。

      目標站點采用 base64加密 c3NwYWkuY29t

      目標數據所在界面如下圖所示:

      通過開發者工具,不斷下拉加載頁面,得到的接口請求規則如下:

      https://Base64加密站點/api/v1/bullet/search/page/get?type=0&limit=10&offset=0&created_at=0 https://Base64加密站點/api/v1/bullet/search/page/get?type=0&limit=10&offset=10&created_at=0 https://Base64加密站點/api/v1/bullet/search/page/get?type=0&limit=10&offset=20&created_at=0 https://Base64加密站點/api/v1/bullet/search/page/get?type=0&limit=10&offset=30&created_at=0

      其中參數除 offset 變化外,其余無變化,其中 limit 參數應該為每個數據量,基于此邏輯,請求接口可以通過代碼進行批量生成,實測過程發現數據量也不大,只有 6 頁。

      下述代碼采用了后進先出隊列 LifoQueue,沒有特殊原因,單純給大家展示一下用法。

      # 初始化一個隊列 q = LifoQueue(maxsize=0) # 批量生成請求地址鏈接 for page in range(1, 7): # https://sspai.com/api/v1/bullet/search/page/get?type=0&limit=10&offset=0&created_at=0 q.put('https://Base64加密站點/api/v1/bullet/search/page/get?type=0&limit=10&offset={}&created_at=0'.format((page-1)*10))

      請求地址批量生成完畢之后,可以開始獲取接口返回的數據了,具體代碼如下,核心關注 main 部分內容。

      # 請求頭函數,可以參考之前的系列文章 def get_headers(): uas = [ "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)" ] ua = random.choice(uas) headers = { "user-agent": ua } return headers # 儲存數據 def save(text): # 文件名使用時間戳命名 with open(f'{time.time()}.json', 'a+', encoding='utf-8') as f: f.write(text) print(text, "--- 保存成功") if __name__ == "__main__": # 判斷隊列是否為空,空則停止循環 while q.qsize() > 0: # 獲取一個 URL url = q.get() # 通知任務已經完成 q.task_done() # 獲取相應數據 res = requests.get(url=url, headers=get_headers(), timeout=10) # 調用保存函數 save(res.text) q.join() print("所有任務都已完成")

      因為上述案例實在太簡單,連多線程都不用,所以我基于【話題廣場】關鍵字,查詢是否還有其它可用于 學習目的 相關站點,結果還真被我發現一個。

      話題廣場 - 集思錄

      集思錄,一個以數據為本的投資社區,https://Python脫敏處理/topic/。

      目標站點使用 base64 編碼:d3d3Lmppc2lsdS5jbg==

      每一個話題下面,都有很多問題,完美符合生產者消費者模型。

      編碼邏輯分析

      【Python技能樹共建】動態渲染頁面爬取 R13

      由于在列表頁之前,還存在一個層級-【熱門話題】,所以需要提前準備好待抓取隊列。

      # 熱門話題列表頁待抓取鏈接 hot_subjects = Queue(maxsize=0) for i in range(1, 11): url = f'https://Python脫敏處理/topic/square/id-hot__feature_id-__page-{i}' hot_subjects.put(url)

      接下來生產函數用于產生列表頁數據,到提前初始化好的 q_data_ids 隊列中,其中 get_headers 函數,參考前文即可。

      def get_headers(): uas = [ "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)" ] ua = random.choice(uas) headers = { "user-agent": ua } return headers # 初始化一個隊列 q_data_ids = Queue(maxsize=0) # 生產函數,用于產生話題列表頁 URL def producer(): while hot_subjects.qsize() > 0: # 取得一個分類頁請求地址 list_url = hot_subjects.get() hot_subjects.task_done() print("正在解析:", list_url) # 獲取話題列表頁相應數據 res = requests.get(list_url, headers=get_headers(), timeout=3) # 解析,獲取話題詳情頁進入的關鍵參數 `data-id`,代碼后有對于該關鍵字的說明 element = etree.HTML(res.text) data_ids = element.xpath('//a[@class="aw-topic-name"]/@data-id') for data_id in data_ids: q_data_ids.put(data_id)

      上述代碼最重要的是捕獲 data-id,即熱門話題的 ID 隊列,該 ID 值會用在消費者函數中,用于請求詳情頁數據。

      接下來就是消費者函數的實現,該邏輯主要用于抓取下圖所示數據。

      以上數據在測試過程中發現如下接口格式,其中 data_id 在生產者中產生,start_page 由循環迭代生成。

      https://Python脫敏處理/question/ajax/discuss/sort_type-new__topic_id-{data_id}__page-{start_page}

      上述地址即為最后目標數據所在地址,我們需要拼湊出標準地址,然后再對 start_page 頁碼,進行迭代,遍歷獲取全部數據。

      學習時請注意下述代碼注釋,技術層級難度不大,重點為實現邏輯。

      # 消費者函數 def consumer(): # 死循環讀取 data_id 值,用于拼湊話題詳情頁數據 while True: # 取一個分類ID data_id = q_data_ids.get() q_data_ids.task_done() if data_id is None: break # start_page 初始值設置為 1,即從第一個開始讀取數據 start_page = 1 # URL 拼接 url = f'https://Python脫敏處理/question/ajax/discuss/sort_type-new__topic_id-{data_id}__page-{start_page}' res = requests.get(url=url, headers=get_headers(), timeout=5) text = res.text # 通過判斷 text 是否為空,確定是否繼續解析數據 while len(text) > 0: url = f'https://Python脫敏處理/question/ajax/discuss/sort_type-new__topic_id-{data_id}__page-{start_page}' res = requests.get(url=url, headers=get_headers(), timeout=5) # print(res.url) text = res.text start_page += 1 # 如果 text 不為空,則解析數據,并存儲數據 if len(text)>0: element = etree.HTML(res.text) titles = element.xpath('//h4/a/text()') urls = element.xpath('//h4/a/@href') names = element.xpath('//a[@class="aw-user-name"]/text()') data = zip(titles,names,urls) save_list = [f"{item[0]},{item[1]},{item[2]}\n" for item in data] long_str = "".join(save_list) with open("./data.csv","a+",encoding="utf-8") as f: f.write(long_str)

      該程序實現的步驟與邏輯相對會繞一些,故通過下圖你可以再復盤進行理解,按照步驟 1,2,3 進行學習。

      函數運行可是采用多線程實現,具體如下:

      # 開啟2個生產者線程 for p_in in range(1, 3): p = threading.Thread(target=producer) p.start() # 開啟2個消費者線程 for p_in in range(1, 2): p = threading.Thread(target=consumer) p.start()

      Python 渲染

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:玩轉Redis學習總結及面試題匯總
      下一篇:華為全面啟航計算戰略:“鯤鵬+昇騰”雙引擎、硬件開放、軟件開源、使能合作伙伴
      相關文章
      亚洲国产成人无码AV在线影院| 亚洲熟女综合色一区二区三区| 激情婷婷成人亚洲综合| 国产精品亚洲精品青青青| 亚洲人成网站18禁止久久影院| 一区二区三区亚洲| 老汉色老汉首页a亚洲| 亚洲AV日韩AV鸥美在线观看| 亚洲阿v天堂在线| 亚洲s色大片在线观看| 亚洲A∨无码无在线观看| 亚洲AV日韩AV永久无码下载| 久久久久亚洲AV片无码| 亚洲欧洲第一a在线观看| 日韩精品亚洲人成在线观看| 777亚洲精品乱码久久久久久| 亚洲色图在线观看| 亚洲经典在线中文字幕| 亚洲av无码久久忘忧草| 在线观看亚洲AV日韩AV| MM1313亚洲国产精品| 亚洲国产精品综合久久网络| 亚洲日韩中文字幕日韩在线| 伊人亚洲综合青草青草久热| 亚洲精品无码MV在线观看| 亚洲av伊人久久综合密臀性色 | 亚洲精品自偷自拍无码| 亚洲欧洲无码一区二区三区| 亚洲Av无码国产一区二区| 亚洲国产精品成人AV在线| 国产亚洲情侣久久精品| 一本色道久久综合亚洲精品高清| 中文字幕精品亚洲无线码一区| 国产亚洲精品资源在线26u| 91天堂素人精品系列全集亚洲| 亚洲国产精品线观看不卡| 亚洲欧洲免费无码| 亚洲无码精品浪潮| 亚洲AV乱码一区二区三区林ゆな | 亚洲aⅴ无码专区在线观看春色| 国产亚洲精品仙踪林在线播放|