首頁  >  文章  >  後端開發  >  面對JS渲染的網頁如何分析Ajax請求

面對JS渲染的網頁如何分析Ajax請求

爱喝马黛茶的安东尼
爱喝马黛茶的安东尼轉載
2019-06-05 18:03:023659瀏覽

我們在用python進行爬蟲時,可能都遇到過有些網頁直接請求得到的HTML 程式碼裡面,並沒有我們需要的數據,也就是我們在瀏覽器中看到的內容。

這就是因為這些資訊是透過Ajax載入的,並且透過js渲染產生的。這時候我們就需要分析這個網頁的請求了。

上一篇跟大家講解了什麼是Cookie及模擬登入的操作流程,今天帶給大家的是如何分析網頁的Ajax請求。

面對JS渲染的網頁如何分析Ajax請求

什麼是Ajax

AJAX即「Asynchronous Javascript And XML」(非同步JavaScript和XML),是指一種創建互動式網頁應用的網頁開發技術。
AJAX = 非同步 JavaScript和XML(標準通用標記語言的子集)。
AJAX 是一種用於建立快速動態網頁的技術。
AJAX 是一種在無需重新載入整個網頁的情況下,能夠更新部分網頁的技術。

簡單的說就是網頁加載,瀏覽器網址列的網址並沒有變,是javascript異步加載的網頁,應該是ajax。 AJAX一般是透過XMLHttpRequest 物件介面發送請求的,XMLHttpRequest 一般被縮寫為 XHR。

分析果殼網站點

我們目標網站就以果殼網來進行分析。

我們可以看到這個網頁並沒有翻頁按鈕,而當我們一直往下拉請求,網頁會自動的給我們加載更多內容。但是,當我們觀察網頁url時,發現它並沒有隨著網頁的載入請求而改變。而當我們直接請求這個url時,顯然我們只能得到到第一頁的html內容。

面對JS渲染的網頁如何分析Ajax請求

那我們要怎麼取得所有頁面的資料呢?

我們在Chrome中開啟開發者工具(F12)。我們點選Network,點選XHR標籤。然後我們刷新網頁,往下拉請求。這時候我們就可以看到XHR標籤,在網頁每次載入的時候就會跳出一個請求。

我們點擊第一個請求,可以看到他的參數:

retrieve_type:by_subject
limit:20
offset:18
-:1500265766286

在點擊第二個請求,參數如下:

retrieve_type:by_subject
limit:20
offset:38
-:1500265766287

limit參數是網頁每一頁限制載入的文章數,offset就是頁數了。接著往下看,我們會發現每個請求的offset參數都會加 20。

我們接著看每個請求的回應內容,這是一個就是格式的資料。我們點開result鍵,可以看到一個 20 篇文章的資料資訊。這樣我們就成功找到我們需要的資訊位置了,我們可以在請求頭中看到存放json資料的url位址。 http://www.guokr.com/apis/minisite/article.json?retrieve_type=by_subject&limit=20&offset=18

面對JS渲染的網頁如何分析Ajax請求

爬取流程

分析Ajax請求取得每一頁的文章url資訊;解析每一篇文章,取得需要資料;將獲得的資料保存資料庫;開啟多進程,大量抓取。

開始

我們的工具仍然使用requests請求,BeautifulSoup解析。

首先我們要透過分析Ajax請求,獲得所有頁的信息,透過對上面對網頁的分析,可以得到Ajax載入的json資料的URL位址為:

http://www. guokr.com/apis/minisite/article.json?retrieve_type=by_subject&limit=20&offset=18

我們需要建構這個URL。

# 导入可能要用到的模块
import requests
from urllib.parse import urlencode
from requests.exceptions import ConnectionError
 
# 获得索引页的信息
def get_index(offset):
    base_url = 'http://www.guokr.com/apis/minisite/article.json?'
    data = {
        'retrieve_type': "by_subject",
        'limit': "20",
        'offset': offset
    }
    params = urlencode(data)
    url = base_url + params
 
    try:
        resp = requests.get(url)
        if resp.status_code == 200:
            return resp.text
        return None
    except ConnectionError:
        print('Error.')
        return None
###   ######我們把上面分析頁面得到的請求參數建構成一個字典data,然後我們可以手動的構造這個url,但是urllib庫已經給我們提供了一個編碼方法,我們直接使用,就可以構造出完整的url了。然後是標準的requests請求頁面內容。 ###
import json
 
# 解析json,获得文章url
def parse_json(text):
    try:
        result = json.loads(text)
        if result:
            for i in result.get('result'):
                # print(i.get('url'))
                yield i.get('url')
    except:
        pass
###我們使用josn.loads方法解析json,將其轉換成json物件。然後直接透過字典的操作,獲得文章的url位址。這裡使用yield,每次請求返回一個url,降低記憶體的消耗。由於我在後面抓的時候跳出一個json解析的錯誤,這裡直接過濾就好。 ######這裡我們可以試著列印看看,是不是成功運行。 ###

既然获得了文章的url,那么对于获得文章的数据就显得很简单了。这里不在进行详细的叙述。我们的目标是获得文章的标题,作者和内容。
由于有的文章里面包含一些图片,我们直接过滤掉文章内容里的图片就好了。

from bs4 import BeautifulSoup
 
# 解析文章页
def parse_page(text):
    try:
        soup = BeautifulSoup(text, 'lxml')
        content = soup.find('div', class_="content")
        title = content.find('h1', id="articleTitle").get_text()
        author = content.find('div', class_="content-th-info").find('a').get_text()
        article_content = content.find('div', class_="document").find_all('p')
        all_p = [i.get_text() for i in article_content if not i.find('img') and not i.find('a')]
        article = '\n'.join(all_p)
        # print(title,'\n',author,'\n',article)
        data = {
            'title': title,
            'author': author,
            'article': article
        }
        return data
    except:
        pass

   

这里在进行多进程抓取的时候,BeautifulSoup也会出现一个错误,依然直接过滤。我们把得到的数据保存为字典的形式,方便保存数据库。

接下来就是保存数据库的操作了,这里我们使用Mongodb进行数据的存储。

import pymongo
from config import *
 
client = pymongo.MongoClient(MONGO_URL, 27017)
db = client[MONGO_DB]
 
def save_database(data):
    if db[MONGO_TABLE].insert(data):
        print('Save to Database successful', data)
        return True
    return False

我们把数据库的名字,和表名保存到config配置文件中,在把配置信息导入文件,这样会方便代码的管理。

最后呢,由于果壳网数据还是比较多的,如果想要大量的抓取,我们可以使用多进程。

from multiprocessing import Pool
 
# 定义一个主函数
def main(offset):
    text = get_index(offset)
    all_url = parse_json(text)
    for url in all_url:
        resp = get_page(url)
        data = parse_page(resp)
        if data:
            save_database(data)
 
if __name__ == '__main__':
    pool = Pool()
    offsets = ([0] + [i*20+18 for i in range(500)])
    pool.map(main, offsets)
    pool.close()
    pool.join()

   

函数的参数offset就是页数了。经过我的观察,果壳网最后一页页码是 12758,有 637 页。这里我们就抓取 500 页。进程池的map方法和Python内置的map方法使用类似。

面對JS渲染的網頁如何分析Ajax請求

好了,对于一些使用Ajax加载的网页,我们就可以这么抓取了。

以上是面對JS渲染的網頁如何分析Ajax請求的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除