通過分析Ajax請求抓取【今日頭條】“街拍”美圖
有一些網頁直接請求得到的HTML程式碼並沒有在網頁中看到的內容,因為一些資訊是通過Ajax載入,並通過js渲染生成的,這時就需要通過分析網頁的請求來獲取想要爬取的內容。本文通過抓取今日頭條街拍美圖講解一下具體操作步驟。
網路庫:Requests
解析庫:BeautifulSoup+正則表示式
儲存資料庫:MongoDB
其他庫:PyMongo
請確保以上庫已經正確安裝。
目標站點分析
開啟今日頭條的網頁並搜尋“街拍”。
我們想要抓取的是這些圖集裡面的內容。
右擊空白處->審查->Network->勾選Preserve log->重新整理網頁
檢視URL返回的都是一些js,並沒有我們想要獲取的內容。
點選XHR,再選中一個URL,檢視請求的方法,發現是用get方法,所以使用requests庫。
再看Preview,裡面有許多data。我們展開來核對一下。
核對一下第一個data的title是不是和當前頁面的第一個標題相同呢?如果是,那麼說明當前網頁的展示和對應的程式碼是沒有問題的。並且URL的對應也沒有問題。
現在下拉頁面,可以看到左下方不斷出現了新的URL請求:
重點在於都是通過offset這個引數的改變來實現的——變化範圍為0,20,40···!那麼我們通過迴圈就可以拿到這個“街拍”下組圖形式的所有資料了!通過右邊的資料可以看到這些都是一些json的資料,我們拿到後臺資料後只需要呼叫json的包進行解析就可以了。
接下來就是分析查詢圖集詳細頁的程式碼,來找到圖片的url,這個圖片url隱藏的比較深,都在JS程式碼中:
通過比對發現確實如此。
由於這個url是藏在gallery這個變數裡的,然而這個變數並不是在html程式碼裡的,所以不能使用BeautifulSoup和PyQuery來解析了,只能通過正則表示式來解析。
流程框架
1.獲取索引頁內容
利用requests請求目標站點,得到索引網頁HTML程式碼,返回結果。
2.抓取詳情頁資訊
解析返回結果,得到詳情頁的連結,並進一步抓取詳情頁的資訊。
3.下載圖片與儲存資料庫
將圖片下載到本地,並把頁面資訊及圖片URL儲存至MongoDB。
4.開啟迴圈及多執行緒
對多頁內容遍歷,開啟多執行緒提高抓取速度。
爬蟲實戰
1.獲取索引頁
再看一下索引頁的請求方式:
我們只需要按照這個格式構建一個Ajax請求。
注意!cur_tab為3時,搜尋到的才是圖集(一共有4個標籤:綜合、視訊、圖集、使用者)。
from urllib.parse import urlencode
import requests
from requests.exceptions import RequestException
headers = {'User-Agent':'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)AppleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36'}#這個資訊是自定義的,根據自身需求來改變
#請求索引頁(索引頁中包含著許多圖集的url)
def get_page_index():
data = {#定義一個data字典,用於Ajax請求
'offset': 0,
'format': 'json',
'keyword': '街拍',
'autoload': 'true',
'count': '20',
'cur_tab': '3',
'from': 'gallery'#這一行一定不能少
}
url = 'https://www.toutiao.com/search_content/?'+urlencode(data)
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
print("請求索引頁錯誤")
return None
def main():
html=get_page_index()
print(html)
if __name__ == '__main__':
main()
注意!由於不同瀏覽器請求時的headers資訊是不同的,所以在定義headers時可以到你的常用瀏覽器中去獲取,隨意開啟一個網頁右鍵審查,點選一個元素network然後檢視Headers:
可以把下圖紅框中的資訊複製到程式碼中作為headers(注意格式是個字典)。
執行一下:
如上,成功獲得了索引頁的html,裡面包含著許多圖集的url。
2.解析索引頁
由於上文返回的html是json格式的字串物件——我們呼叫type方法就可以看出來:
print(type(html))
因此我們需要呼叫json.loads()方法對字串進行解析。
json.loads()用於將str型別的資料轉成字典。
再仔細分析下圖,這是索引頁的html(json格式)。可以看到,data對應還有許多值。
將這些值(0,1,2…)展開,可以看到每一個值又是一個字典(abstract,article_url…),我們要提取的就是這些子層字典中“article_url”對應的值。
#注意引入相關的包
import json
from json.decoder import JSONDecodeError
#傳入索引頁的html,解析出每個圖集的url
def parse_page_index(html):
try:#加入異常處理
data = json.loads(html)#對html進行解析,轉換為字典。
if data and 'data' in data.keys():
#data.keys()返回的是這個字典中的所有的鍵名,並判斷:'data'這個鍵名是否其中,若在的話執行下面的for迴圈
for item in data.get('data'):#data這個鍵對應著許多值,遍歷這些值,並依次賦值給item
yield item.get('article_url')#構造一個生成器,取出每一個item中的article_url對應的url
except JSONDecodeError:#如果出現了JSON解析異常,則跳過
pass
然後在main函式中呼叫以上的函式,解析出圖集的url,這些url就是每個圖集的入口。
def main():
html=get_page_index()
for url in parse_page_index(html):#通過生成器提取所有的url
print(url)
很好,當前索引頁中,所有的圖集url都被我們提取到了。
3.獲取詳情頁
若嘗試進入上面提取到的url,那麼則會進入詳情頁(也就是進入了某個圖集)。現在我們要獲取詳情頁的程式碼(因為我們最終要抓取的圖片就隱藏在這些程式碼之中)。這部分很好理解,和1.獲取索引頁的程式碼是相同的。
#請求每個圖集的詳情頁
def get_page_detail(url):
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
print('請求詳情頁出錯',url)
return None
再次在main函式中改動一下,把上面獲取到的詳情頁的text列印一下,以此來檢查到此為止一切是否順利:
def main():
html=get_page_index()
for url in parse_page_index(html):#通過生成器提取所有的url
print(get_page_detail(url))#依次請求(上面提取到的url)並列印返回的text
好,成功請求了url,並且得到了它們的text。通過type()可以知道,這些text都是str型別的。
4.解析詳情頁資料
關鍵的一步到了。我們先研究一下詳情頁的原始碼。
要在“Doc”中才能看到比較原始的程式碼。我們再找找圖片的url隱藏在哪裡。
發現圖片的url都在gallery鍵的值中(並且值裡面還有許多的“\”符號)
現在定義一個函式來解析詳情頁的資料,目標是把這個圖集下的所有圖片url提取出來。
首先,獲取每個圖片集的標題title,用BeautifulSoup下的select方法選擇title標籤下的文字。(因為文字直接能用,所以這時候就可以使用特別方便的BeautifulSoup了,而下面的圖片url就不是這樣,還摻雜著別的資訊)
from bs4 import BeautifulSoup#記得匯入
#解析詳情頁,獲取圖集中每張圖片的url
def parse_page_detail(html):
soup = BeautifulSoup(html,'lxml')#傳入解析器:lxml和解析物件:html
title = soup.select('title')[0].get_text()
#因為select返回的結果是一個list,所以要用[0]來指定元素(也就是第一個元素),這個元素的型別是bs4.element.Tag
#get_text()方法是定義在bs4.element.Tag這個類上面的,而不是list上
#get_text()方法獲取“title”對應的內容
print(title)
在main函式中判斷html是否正確,並列印結果:
main():
html = get_page_index()
for url in parse_page_index(html):
html = get_page_detail(url)
if html:
parse_page_detail(html)
接下來獲取每個圖片集中的圖片資訊,所有圖片資訊都在gallery鍵的值中,通過re.comlile構建一個正則表示式pattern,再search得到結果,因為此時得到的結果中資訊不正確,有很多多餘的反斜槓’\’,於是利用replace去掉斜槓。
這一步的關鍵是正則表示式的寫法。
注意,由於不同的瀏覽器返回的程式碼有可能不同,所以根據自己在瀏覽器(這個瀏覽器的headers應該與程式碼中的相對應,否則可能出錯)中看到的程式碼來寫正則表示式。
我們要匹配的是上圖藍色框中的內容(夾在括號內)。
import re
#下面提取json串,串中包含了圖片資訊
images_pattern = re.compile('JSON.parse\("(.*?)"\),', re.S)#注意對括號進行轉義
result=re.search(images_pattern,html)
if result:
result = result.group(1).replace('\\', '')#替換反斜槓為空格
結果是json字串的格式,需要用loads解析,提取其中的每張照片的url,最後返回的是圖集的標題、連結和每張圖片的url。
以上一步的思路進一步完善:
def parse_page_detail(html,url):#多傳入一個當前詳情頁的url引數
soup = BeautifulSoup(html,'lxml')#傳入解析器:lxml和解析物件:html
title = soup.select('title')[0].get_text()
#get_text()方法獲取“title”對應的內容
print(title)
# 下面提取json串,串中包含了圖片資訊
images_pattern = re.compile('JSON.parse\("(.*?)"\),', re.S) # 注意對括號進行轉義
result = re.search(images_pattern, html)
if result:
result = result.group(1).replace('\\', '')
data = json.loads(result) # 轉換成json物件
if data and 'sub_images' in data.keys():
sub_images = data.get('sub_images')
# 每個sub_images都是一個字典,需要遍歷它來提取url元素
# 用一句話來構造一個list,把item賦值為sub_images的每一個子元素
# 再取得sub_images的每一個item物件的url屬性,完成列表的構建,這個列表名為images,裡面是sub_images下所有的url
images = [item.get('url') for item in sub_images]
return { # 以一個字典形式返回
'title': title,
'url': url, # 這是當前詳情頁的url
'images': images
}
此時,所有的資訊已經提取完畢,開始儲存資料到MongoDB資料庫。
儲存到資料庫
要把資料儲存到mongodb資料庫中,首先在同一目錄下,建立配置檔案config.py。
這個配置檔案需要寫入以下內容:
MONGO_URL='localhost' #連結地址
MONGO_DB='toutiao' #資料庫
MONGO_TABLE='toutiao' #資料集即“表”
通過from config import *呼叫該檔案:
from config import *
import pymongo
#宣告mongodb資料庫物件
client=pymongo.MongoClient(MONGO_URL)
db=client[MONGO_DB]
然後定義函式儲存到資料庫中,並判斷如果儲存成功輸出相應資訊
#把url儲存到資料庫
def save_to_mongo(result):
if db[MONGO_TABLE].insert(result):
print('儲存到MongoDB成功',result)
return True
return False
這個函式將在主函式中呼叫:
def main(offset):
html=get_page_index(offset, KEYWORD)
for url in parse_page_index(html):#獲得每個圖集的url
html=get_page_detail(url)#用某個圖集的url來請求詳情頁
if html:
result=parse_page_detail(html,url)#解析詳情頁的資訊
if result:save_to_mongo(result)#儲存到資料庫
6.下載圖片
首先定義一個函式,利用pathlib庫,根據傳入的目錄名建立一個檔案目錄,這是為了將圖片分類:
from pathlib import Path
def create_dir(name):
#根據傳入的目錄名建立一個目錄,這裡用到了 python3.4 引入的 pathlib 。
directory = Path(name)
if not directory.exists():
directory.mkdir()
return directory
然後定義下載圖片函式,要求返回的是content,是二進位制檔案:
def download_image(save_dir,url):
print("正在下載:",url)
try:
response = requests.get(url,headers=headers)#還是熟悉的請求方式
if response.status_code == 200:
#呼叫儲存圖片函式,返回二進位制
save_image(save_dir,response.content)#呼叫儲存圖片的函式
return None
except RequestException:
print("請求圖片出錯",url)
return None
定義儲存圖片函式
import os
from hashlib import md5
def save_image(save_dir,content):
'''把檔案儲存到本地,檔案有三部分內容(路徑)/(檔名).(字尾)
用format構造字串(專案路徑,檔名,格式),md5檔名可以避免重複'''
#os.getcwd()程式同目錄,但是現在我們要自定義目錄
#file_path='{0}/{1}.{2}'.format(os.getcwd(),md5(content).hexdigest(),'jpg')
file_path = '{0}/{1}.{2}'.format(save_dir, md5(content).hexdigest(), 'jpg')
#如果檔案不存在,開始存入
if not os.path.exists(file_path):
with open(file_path,'wb') as f:
f.write(content)
f.close()
在parse_page_detail函式中,呼叫download_image:
root_dir=create_dir('E:\spider\\'+KEYWORD) # 儲存圖片的根目錄,這個是自定義的,E:\spider這個資料夾需要提前在本地建好。此後程式會根據KEYWORD建一個子資料夾。create_dir函式是上面我們定義過的。
download_dir = create_dir(root_dir / title) # 根據每組圖片的title標題名建立目錄
for image in images:
download_image(download_dir, image) #下載所有的圖片
為了方便程式碼的複用,還可以把offset、搜尋關鍵詞等引數放到配置檔案中:
MONGO_URL='localhost' #連結地址
MONGO_DB='toutiao' #資料庫
MONGO_TABLE='toutiao' #資料集即表
GROUP_START = 1
GROUP_END = 20
KEYWORD = '街拍'#若想爬取其他內容,在此替換關鍵詞即可
7.開啟迴圈及多執行緒
開啟多執行緒可以提高抓取效率:同時下載多個頁面的圖片
迴圈可以抓取更多頁面的資訊
from multiprocessing import Pool
if __name__ == '__main__':
groups = [x*20 for x in range(GROUP_START,GROUP_END+1)]
#把offset做成一個列表20,40,60...
#GROUP_START,GROUP_END用來限制起始和結束時的offset,也就是想要爬取的頁面範圍,這已在配置檔案中定義過了
pool=Pool()
pool.map(main,groups)#將列表傳入主函式,並且開啟多執行緒
還需要修改:
將請求索引頁時的offset和keyword改為由呼叫方(主函式)傳入
修改主函式:
offset是由上面的groups列表傳入, KEYWORD是在配置檔案中定義的。
def main(offset):
html=get_page_index(offset, KEYWORD)
完整程式碼:
import requests
from urllib.parse import urlencode
from requests.exceptions import RequestException
import json
from bs4 import BeautifulSoup
import re
from config import *
import pymongo
import os
from hashlib import md5
from multiprocessing import Pool
from json.decoder import JSONDecodeError
from pathlib import Path
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'}
#宣告mongodb資料庫物件
client = pymongo.MongoClient(MONGO_URL,connect=False)
db = client[MONGO_DB]
#請求索引頁(索引頁中包含著許多圖集的url)
def get_page_index(offset,keyword):
data = {#定義一個data字典,用於Ajax請求
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': '20',
'cur_tab': '3',
'from': 'gallery'
}
url='http://www.toutiao.com/search_content/?'+urlencode(data)
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
print('請求索引頁出錯')
return None
#傳入索引頁的html,解析出每個圖集的url
def parse_page_index(html):
try:#加入異常處理
data = json.loads(html)#對html進行解析,轉換為字典。
if data and 'data' in data.keys():#data.keys()返回的是這個json的所有的鍵名,這裡判斷'data'在這些鍵名中
for item in data.get('data'):#data對應還有許多值,遍歷這些值
yield item.get('article_url')#構造一個生成器,取出data中的每一個article_url對應的url
except JSONDecodeError:
pass
#請求每個圖集的詳情頁
def get_page_detail(url):
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
print('請求詳情頁出錯',url)
return None
#解析詳情頁,獲取圖集中每張圖片的url
def parse_page_detail(html,url):
soup = BeautifulSoup(html, 'lxml')
# 用BeautifulSoup來提取title資訊
title = soup.select('title')[0].get_text()
print(title)
#下面提取json串,串中包含了圖片資訊
images_pattern = re.compile('JSON.parse\("(.*?)"\),', re.S)#注意對括號進行轉義
result=re.search(images_pattern,html)
if result:
result = result.group(1).replace('\\', '')
data = json.loads(result)#轉換成json物件
if data and 'sub_images' in data.keys():
sub_images = data.get('sub_images')
#每個sub_images都是一個字典,需要遍歷它來提取url元素
# 用一句話來構造一個list,把item賦值為sub_images的每一個子元素
# 再取得sub_images的每一個item物件的url屬性,完成列表的構建,這個列表名為images,裡面是sub_images下所有的url
images = [item.get('url') for item in sub_images]
root_dir=create_dir('E:\spider\jiepai')
download_dir = create_dir(root_dir/title)
for image in images: download_image(download_dir,image)#通過迴圈把圖片下載下來
return {#以一個字典形式返回
'title':title,
'url':url,#這是當前詳情頁的url
'images':images
}
#把url儲存到資料庫
def save_to_mongo(result):
if db[MONGO_TABLE].insert(result):
print('儲存到MongoDB成功',result)
return True
return False
#通過url來請求圖片
def download_image(save_dir,url):
print('正在下載',url)
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
save_image(save_dir,response.content)#content返回的是二進位制內容,一般處理圖片都用二進位制流
return response.text
return None
except RequestException:
print
相關推薦
通過分析Ajax請求抓取【今日頭條】“街拍”美圖
有一些網頁直接請求得到的HTML程式碼並沒有在網頁中看到的內容,因為一些資訊是通過Ajax載入,並通過js渲染生成的,這時就需要通過分析網頁的請求來獲取想要爬取的內容。本文通過抓取今日頭條街拍美圖講解一下具體操作步驟。
網路庫:Requests 解析庫:BeautifulSoup+正則表
通過分析Ajax請求抓取【今日頭條】街拍美圖
有一些網頁直接請求得到的HTML程式碼並沒有在網頁中看到的內容,因為一些資訊是通過Ajax載入,並通過js渲染生成的,這時就需要通過分析網頁的請求來獲取想要爬取的內容。本文通過抓取今日頭條街拍美圖講解一下具體操作步驟。
網路庫:Requests
解析庫:Beau
分析Ajax請求並抓取今日頭條街拍美圖
mage param word esp 信息 ons import src on() 準備工作
requests、Beautiful Soup、MongoDB
抓取分析
在抓取之前首先分析抓取的邏輯,打開今日頭條的首頁https://www.toutiao.com/如
分析Ajax抓取今日頭條街拍美圖
resp exce ret splay pattern hashlib multi re.search clas spider.py
1 # -*- coding:utf-8 -*-
2 from urllib import urlencode
3 impo
分析ajax介面抓取今日頭條
抓取ajax網站可以通過分析ajax介面的方式獲取到返回的json資料,從而抓取到我們想要的資料,以今日頭條為例,如何分析ajax介面,模擬ajax請求爬取資料。
以今日頭條的街拍為例,網頁上一頁只顯示部分資料,檢視後續資料需要滑鼠下滑,這裡
【爬蟲入門】抓取今日頭條的街拍搜尋頁的圖片,並儲存到資料庫和本地
使用多程序對街拍圖片進行下載,並將圖片相關資訊儲存到mongodb資料庫中。
import requests, re, json, pymongo
from multiprocessing import Pool
from urllib.parse import urlencode
f
分析Ajax爬取今日頭條街拍美圖-崔慶才思路
站點分析原始碼及遇到的問題程式碼結構方法定義需要的常量關於在程式碼中遇到的問題01. 資料庫連線02.今日頭條的反爬蟲機制03. json解碼遇到的問題04. 關於response.text和response.content的區別原始碼
站點分析
首先,開啟頭條,在搜尋框輸入關鍵字之後,在返回的
抓取今日頭條的街拍美女圖片
由於今日頭條的反扒機制的更新,利用多執行緒,將圖片儲存在資料夾中,將路徑儲存在mongo db中
import codecs
import pymongo
import requests
import json
import re
import os
from hashlib import md
Ajax爬取今日頭條街拍美圖
1.開啟今日頭條:https://www.toutiao.com
2.搜尋街拍
3.檢查元素,檢視請求發現在URL中每次只有offset發生改變,是一個get請求
1 import requests
2 from urllib.parse import urlencode
3 impor
Python web爬取今日頭條的街拍
#最新的暫時能用
import requests
from urllib.parse import urlencode
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_
【今日頭條】今日頭條三面面經
一面:
(1) 演算法題,程式設計實現nsum
(2)實現元素的居中並且寬高比為3:4
(3)程式碼實現繼承
(4)給了一段程式碼給出輸出結果,這個是和非同步相關
(5)http的狀態碼有哪些
【今日頭條】【實習】放出一大波職位
後臺開發實習生"後臺開發實習生
職位職責:
1.負責相關產品的後臺開發工作
2.主要實現語言python和golang
職位要求:
1.良好的設計和編碼品味,熱愛寫程式碼
2.較好的產品意識,願意將產品效果做為工作最重要的驅動因素
3.掌握WEB後端開發技術:
【今日頭條】演算法工程師 ~ 等你來投遞!
今日頭條社招今日頭條演算法工程師(這是社招哦)
職位描述 :
基於機器學習, 優化頭條新產品的排序, 提升使用者體驗
在這裡, 你有機會見證一個產品從0到1的過程, 在演算法,工程,產品上得到全方面的鍛鍊
基本要求 :
1. 熟悉常見演算法, 如LR, GBDT, DNN,
【今日頭條】【招聘】後臺研發工程師--java,前端開發工程師
測試開發(高階)工程師
崗位職責:
1、主要負責公司移動端產品質量保障工作;
2、日常專案線下測試與線上質量分析;
3、對專案中的問題進行監控、追查及定位;
4、學習和研究新技術以提高測試效率和質量;
5、對產品提出改進建議以建立極致的使用者感受,對專案提出改進建議以提高
通過分析ajax,使用正則表示式爬取今日頭條
今日頭條是一個動態載入頁面的網站,這一類的網站直接使用requests爬取的話得不到我們想要的內容。所以一般這類的網站都是通過分析ajax來進行抓包來獲取我們想要的內容。
老規矩,首先列出需要引入的庫:
import json
import os
from urllib.
python 通過ajax請求爬取今日頭條內容(僅程式碼+註釋+執行結果)
學習書籍:《python3 網路爬蟲開發實戰》 –崔慶才
前提:下好MongoDB,以及各種第三方庫
test.py
import json
import os
import re
from hashlib import md5
import pymo
【R語言爬蟲】R語言提交get請求抓取城城理財資料
二、實現原始碼
rm(list=ls())
library(XML)
library(RCurl)
url='https://www.cclc.co/debts/lctz_all_all'
爬蟲[1]---頁面分析及資料抓取
頁面分析及資料抓取
anaconda + scrapy 安裝:https://blog.csdn.net/dream_dt/article/details/80187916 用 scrapy 初始化一個爬蟲:https://blog.csdn.net/dream_dt/article
對Soul 安卓App的一次 api請求 抓取記錄
之前註冊玩過一段時間的社交app--soul,發現其沒有網頁版也沒有桌面版,app裡也沒有相關的資料匯出功能,作為一個老使用者,很多日常釋出的瞬間很想匯出來,作為紀念,所以就想看看能不能指令碼抓取我的資料,才有了下面的記錄:
一.對soul抓包
分析Soul App
[Python]網路爬蟲(二):利用urllib2通過指定的URL抓取網頁內容
版本號:Python2.7.5,Python3改動較大,各位另尋教程。
所謂網頁抓取,就是把URL地址中指定的網路資源從網路流中讀取出來,儲存到本地。
類似於使用程式模擬IE瀏覽器的功能,把URL作為HTTP請求的內容傳送到伺服器端, 然後讀取伺服器端的響應資源。
在