python 通過ajax請求爬取今日頭條內容(僅程式碼+註釋+執行結果)
阿新 • • 發佈:2019-02-19
學習書籍:《python3 網路爬蟲開發實戰》 –崔慶才
前提:下好MongoDB,以及各種第三方庫
- test.py
import json
import os
import re
from hashlib import md5
import pymongo
from urllib.parse import urlencode
import requests
from bs4 import BeautifulSoup
from requests.exceptions import RequestException
from config import *
#引入多程序
from multiprocessing import Pool
#宣告一個MongoDB資料庫物件
client=pymongo.MongoClient(MONGO_URL,connect=False)
db=client[MONGO_DB]
#獲取索引
def get_page_index(offset,keyword):
data={
'offset':offset,
'format':'json',
'keyword':keyword,
'autoload':'true',
'count': '20',
'cur_tab':'3',
'from' : 'search_tab'
}
#進行編碼,加上引數
url='https://www.toutiao.com/search_content/?'+urlencode(data)
try:
response=requests.get(url)
if response.status_code == 200:
return response.text
return None
except RequestException:
print('請求索引失敗')
return None
#解析索引頁面,即搜尋出來的一個個總集合。需要獲取詳情頁面的url
def parse_page_index(html):
try:
#通過loads將字串轉換成物件
data=json.loads(html)
#使用了dict.keys()方法,返回所有鍵值
if data and 'data' in data.keys():
for item in data.get('data'):
yield item.get('article_url')
finally:
print('解鎖成功')
#獲取詳情
def get_page_detail(url):
try:
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}
response=requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
print('請求詳情頁面失敗',url)
return None
#解析獲取的HTML為json格式
def parse_page_detail(html,url):
soup=BeautifulSoup(html,'lxml')
title=soup.select('title')[0].get_text()
images_pattern=re.compile('gallery: JSON.parse\\((.*?)\\),',re.S)
result=re.search(images_pattern,html)
if result:
#網頁格式改了,需要解析2次才能正確解析
data=json.loads(json.loads(result.group(1)))
if data and 'sub_images' in data.keys():
sub_images=data.get('sub_images')
#遍歷sub_images,並獲取其中鍵值為url的資料,放入陣列中
images=[item.get('url') for item in sub_images]
#已經獲取到所有圖片,迴圈,呼叫下載函式
for image in images:download_image(image)
return {
'title':title,
'url':url,
'images':images
}
#儲存到資料庫,引數採用一個字典
def save_to_mongo(result):
if db[MONGO_TABLE].insert(result):
print('儲存成功',result)
return True
return False
#下載(注意,這裡和前面不一樣的是請求response.content
# content是返回二進位制內容,text返回網頁請求結果
#一般請求網頁用text,請求圖片用content
def download_image(url):
print('正在下載:',url)
try:
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}
response=requests.get(url,headers=headers)
if response.status_code == 200:
save_image(response.content)
return None
except RequestException:
print('請求圖片下載出錯',url)
return None
#將download_image中獲取的response.text作為引數傳入
def save_image(content):
#路徑包含三部分:哪個資料夾,圖片名,圖片字尾
#為了防止下重複的圖片,使用md5來防止
file_path='{0}/{1}.{2}'.format('F:\\image\\',md5(content).hexdigest(),'jpg')
#如果檔案不存在,就儲存下來
if not os.path.exists(file_path):
with open(file_path,'wb') as f:
f.write(content)
f.close()
def main(offset):
#KEYWORD在配置檔案中
html=get_page_index(offset,KEYWORD)
for url in parse_page_index(html):
#此處的html是每個詳情頁面的內容
html=get_page_detail(url)
if html:
result=parse_page_detail(html,url)
save_to_mongo(result)
if __name__=='__main__':
#觀察頭條可發現,向下拉時候會不停發出ajax請求,並且每次
#都是引數offset偏移了20,這裡多程序執行main函式,加上offset引數
#來請求多組資料
groups=[x*20 for x in range(1,20)]
#宣告一個程序池
pool=Pool()
pool.map(main,groups)
2.config.py
#存入MongoDB
MONGO_URL='localhost'
MONGO_DB='toutiao'
MONGO_TABLE='toutiao1'
#定義一個offset偏移量,用於迴圈
GROUP_START=1
GROUP_END=20
#搜尋的關鍵字
KEYWORD='街拍'
3.執行結果截圖: