python动态爬取知乎_python爬虫从小白到高手 Day2 动态页面的爬取
今天我們說說動態(tài)頁面的抓取,動態(tài)頁面的概念不是說網頁上的內容是活動的,而是刷新的內容由Ajax加載,頁面的URL沒有變化,具體概念問度娘。
就以男人都喜歡的美女街拍為例,對象為今日頭條。
chrome打開今日頭條 ->搜索
開發(fā)者工具->network選項卡
圖2-1
很多條目,各種請求,但Ajax其實有其特殊的請求類型,它叫作xhr。在圖6-3中,我們可以發(fā)現一個名稱以getIndex開頭的請求,其Type為xhr,這就是一個Ajax請求。用鼠標點擊這個請求,可以查看這個請求的詳細信息。
圖2-2
選中這個xhr請求后,我們可以看到Request Headers中X-Requested-With:XMLHttpRequest,這就標記了此請求是Ajax請求。
點擊一下Preview,即可看到響應的內容,它是JSON格式的。這里Chrome為我們自動做了解析,點擊箭頭即可展開和收起相應內容,初步分析這里返回的是頁面上顯示出來的前二十條信息。
圖2-3
切換回第一個請求,我們發(fā)現Response中的信息是這樣的
圖2-4
這就是原始鏈接 https://www.toutiao.com/search/?keyword=街拍 所返回的內容,只有六十多行代碼,執(zhí)行了一些JavaScript,所以我們最終看到的頁面不是由初始頁面返回的,而是后來執(zhí)行的JavaScript向服務器發(fā)送了Ajax請求,收到返回的真實數據后才顯示出來的。這就是動態(tài)頁面渲染的流程。
明白了整個流程后,我們要做的最重要的事就是分析返回數據的內容,用python模擬Ajax請求,拿到我們所希望抓取的數據。
def get_page(offset):
params = {
'offset': offset,
'format': 'json',
'keyword': '街拍',
'autoload': 'true',
'count': '20',
'cur_tab': '1',
'from': 'search_tab',
}
url = 'https://www.toutiao.com/search_content/?'
try:
response = requests.get(url, params=params)
if response.status_code == 200:
return response.json()
except requests.ConnectionError:
return None
下滑幾次后,發(fā)現只有offset參數變化,所以,構造url,requests獲得數據
這里拿到的數據是json格式的
def download_image(jsonData):
if jsonData.get('data'):
for item in jsonData.get('data'):
if item and 'article_url' in item.keys():
title = item.get('title')
article_url = item.get('article_url')
result = get_real_image_path(article_url)
if result: save_to_mongo(result)
'''
另外一種數據格式cell,cell type太多,主要分析上面一種
else:
#original_page_url
data = item.get('display')
#print(display)
#data = json.loads(display)
#print(data)
if data and 'results' in data.keys():
results = data.get('results')
original_page_urls = [item.get('original_page_url') for item in results]
# .get('results').get('original_page_url')
#title = item.get('display').get('title')
#print(title)
#print(original_page_urls)'''
取出數據中的data段,發(fā)現只有前四張圖片的地址可以取到,剩下的圖片必須進入文章頁才能獲得,我們取出文章頁的url,requests獲得文章頁數據
def get_real_image_path(article_url):
headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}
response = requests.get(article_url, headers=headers)
soup = BeautifulSoup(response.text, "lxml")
title = soup.select('title')[0].get_text()
image_pattern = re.compile('gallery: JSON.parse\("(.*?)"\),', re.S)
result = re.search(image_pattern, response.text)
if result:
result = result.group(1).replace('\\', '')
data = json.loads(result)
if data and 'sub_images' in data.keys():
sub_images = data.get('sub_images')
images_urls = [item.get('url') for item in sub_images]
for image_url in images_urls: download_real_image(image_url)
return {
'title': title,
'url' : article_url,
'image_urls': images_urls
}
這里需要加入UA頭,否則返回不了數據,拿到數據后,發(fā)現圖片地址位于
圖2-5
這里用正則表達式
gallery: JSON.parse\("(.*?)"\),
匹配符合條件的,gallery: JSON.parse("")中的數據\(\)這里在正則中表達的是轉義字符,有興趣的可以學習一下正則表達式,這里就不贅述了
我們從sub_images中拿到了所有圖片地址,下載過程就很簡單了
requests圖片地址,獲得的response中的content就是圖片的數據
def download_real_image(url):
print('downloading---', url)
try:
response = requests.get(url)
if response.status_code == 200:
save_image(response.content)
return None
except RequestException:
print('request image fail---', url)
return None
def save_image(content):
files_path = '{0}/{1}'.format(os.getcwd(), 'tupian')
if not os.path.exists(files_path):
os.mkdir(files_path)
file_path = '{0}/{1}.{2}'.format(files_path, md5(content).hexdigest(), 'jpg')
if not os.path.exists(file_path):
with open(file_path, 'wb') as f:
f.write(content)
我們還可以把圖片的標題和地址寫入數據庫
def save_to_mongo(result):
if db[MONGO_TABLE].insert(result):
print('save success', result)
return True
return False
完整代碼:jjrt.py
import requests
import re
import json
from hashlib import md5
import os
from bs4 import BeautifulSoup
import pymongo
from config import *
import time
client = pymongo.MongoClient(MONGO_URL, connect=False)
db = client[MONGO_DB]
def get_page(offset):
params = {
'offset': offset,
'format': 'json',
'keyword': '街拍',
'autoload': 'true',
'count': '20',
'cur_tab': '1',
'from': 'search_tab',
}
url = 'https://www.toutiao.com/search_content/?'
try:
response = requests.get(url, params=params)
if response.status_code == 200:
return response.json()
except requests.ConnectionError:
return None
def save_to_mongo(result):
if db[MONGO_TABLE].insert(result):
print('save success', result)
return True
return False
def download_real_image(url):
print('downloading---', url)
try:
response = requests.get(url)
if response.status_code == 200:
save_image(response.content)
return None
except RequestException:
print('request image fail---', url)
return None
def save_image(content):
files_path = '{0}/{1}'.format(os.getcwd(), 'tupian')
if not os.path.exists(files_path):
os.mkdir(files_path)
file_path = '{0}/{1}.{2}'.format(files_path, md5(content).hexdigest(), 'jpg')
if not os.path.exists(file_path):
with open(file_path, 'wb') as f:
f.write(content)
def get_real_image_path(article_url):
headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}
response = requests.get(article_url, headers=headers)
soup = BeautifulSoup(response.text, "lxml")
title = soup.select('title')[0].get_text()
image_pattern = re.compile('gallery: JSON.parse\("(.*?)"\),', re.S)
result = re.search(image_pattern, response.text)
if result:
result = result.group(1).replace('\\', '')
data = json.loads(result)
if data and 'sub_images' in data.keys():
sub_images = data.get('sub_images')
images_urls = [item.get('url') for item in sub_images]
for image_url in images_urls: download_real_image(image_url)
return {
'title': title,
'url' : article_url,
'image_urls': images_urls
}
def download_image(jsonData):
if jsonData.get('data'):
for item in jsonData.get('data'):
if item and 'article_url' in item.keys():
title = item.get('title')
article_url = item.get('article_url')
result = get_real_image_path(article_url)
if result: save_to_mongo(result)
'''
另外一種數據格式cell,cell type太多,主要分析上面一種
else:
#original_page_url
data = item.get('display')
#print(display)
#data = json.loads(display)
#print(data)
if data and 'results' in data.keys():
results = data.get('results')
original_page_urls = [item.get('original_page_url') for item in results]
# .get('results').get('original_page_url')
#title = item.get('display').get('title')
#print(title)
#print(original_page_urls)'''
def main():
STARTPAGE = 1
ENDPAGE = 2
for i in range(STARTPAGE, ENDPAGE):
time.sleep(1)
offset = i * 20
jsonData = get_page(offset)
download_image(jsonData)
if __name__ == "__main__":
main()
config.py
MONGO_URL = 'localhost'
MONGO_DB = 'jiepai'
MONGO_TABLE = 'jiepai'
GROUP_START = 0
GROUP_END = 20
KEYWORD = '街拍'
總結
以上是生活随笔為你收集整理的python动态爬取知乎_python爬虫从小白到高手 Day2 动态页面的爬取的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++输出小数点后几位_Python格式
- 下一篇: 表变量是什么_DAX学习:使用VAR定义