基於Python獲取亞馬遜的評論信息的處理

上次亞馬遜的商品信息都獲取到瞭,自然要看一下評論的部分。用戶的評論能直觀的反映當前商品值不值得購買,亞馬遜的評分信息也能獲取到做一個評分的權重。

亞馬遜的評論區由用戶ID,評分及評論標題,地區時間,評論正文這幾個部分組成,本次獲取的內容就是這些。

測試鏈接:https://www.amazon.it/product-reviews/B08GHGTGQ2/ref=cm_cr_arp_d_paging_btm_14?ie=UTF8&pageNumber=14&reviewerType=all_reviews&pageSize=10&sortBy=recent

一、分析亞馬遜的評論請求

首先打開開發者模式的Network,Clear清屏做一次請求:

你會發現在Doc中的get請求正好就有我們想要的評論信息。

可是真正的評論數據可不是全部都在這裡的,頁面往下翻,有個翻頁的button:

點擊翻頁請求下一頁,在Fetch/XHR選項卡中多瞭一個新的請求,剛才的Doc選項卡中並無新的get請求。這下發現瞭所有的評論信息是XHR類型的請求。

獲取到post請求的鏈接和payload數據,裡面含有控制翻頁的參數,真正的評論請求已經找到瞭。

這一堆就是未處理的信息,這些請求未處理的信息裡面,帶有data-hook=\"review\"的就是帶有評論的信息。分析完畢,下面開始一步一步去寫請求。

二、獲取亞馬遜評論的內容

首先拼湊請求所需的post參數,請求鏈接,以便之後的自動翻頁,然後帶參數post請求鏈接:

headers = {
    'authority': 'www.amazon.it',
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36",
}
 
page = 1
post_data = {
    "sortBy": "recent",
    "reviewerType": "all_reviews",
    "formatType": "",
    "mediaType": "",
    "filterByStar": "",
    "filterByLanguage": "",
    "filterByKeyword": "",
    "shouldAppend": "undefined",
    "deviceType": "desktop",
    "canShowIntHeader": "undefined",
    "pageSize": "10",
    "asin": "B08GHGTGQ2",
}
# 翻頁關鍵payload參數賦值
post_data["pageNumber"] = page,
post_data["reftag"] = f"cm_cr_getr_d_paging_btm_next_{page}",
post_data["scope"] = f"reviewsAjax{page}",
# 翻頁鏈接賦值
spiderurl=f'https://www.amazon.it/hz/reviewsrender/ajax/reviews/get/ref=cm_cr_getr_d_paging_btm_next_{page}'
res = requests.post(spiderurl,headers=headers,data=post_data)
if res and res.status_code == 200:
    res = res.content.decode('utf-8')
    print(res)

現在已經獲取到瞭這一堆未處理的信息,接下來開始對這些數據進行處理。

三、亞馬遜評論信息的處理

上圖的信息會發現,每一段的信息都由“&&&”進行分隔,而分隔之後的每一條信息都是由'","'分隔開的:

所以用python的split方法進行處理,把字符串分隔成list列表:

# 返回值字符串處理
contents = res.split('&&&')
for content in contents:
    infos = content.split('","')

由'","'分隔的數據通過split處理生成新的list列表,評論內容是列表的最後一個元素,去掉裡面的"\","\n"和多餘的符號,就可以通過css/xpath選擇其進行處理瞭:

for content in contents:
    infos = content.split('","')
    info = infos[-1].replace('"]','').replace('\\n','').replace('\\','')
    # 評論內容判斷
    if 'data-hook="review"' in info:
        sel = Selector(text=info)
        data = {}
        data['username'] = sel.xpath('//span[@class="a-profile-name"]/text()').extract_first() #用戶名
        data['point'] = sel.xpath('//span[@class="a-icon-alt"]/text()').extract_first() #評分
        data['date'] = sel.xpath('//span[@data-hook="review-date"]/text()').extract_first() #日期地址
        data['review'] = sel.xpath('//span[@data-hook="review-title"]/span/text()').extract_first() #評價標題
        data['detail'] = sel.xpath('//span[@data-hook="review-body"]').extract_first() #評價內容
        image = sel.xpath('div[@class="review-image-tile-section"]').extract_first()
        data['image'] = image if image else "not image" #圖片
        print(data)

四、代碼整合

4.1 代理設置

穩定的IP代理是你數據獲取最有力的工具。目前國內還是無法穩定的訪問亞馬遜,會出現連接失敗的情況。我這裡使用的ipidea代理請求的意大利地區的亞馬遜,可以通過賬密和api獲取代理,速度還是非常穩定的。

地址:http://www.ipidea.net/?utm-source=csdn&utm-keyword=?wb

下面的代理獲取的方法:

# api獲取ip
    def getApiIp(self):
        # 獲取且僅獲取一個ip------意大利
        api_url = '獲取代理地址'
        res = requests.get(api_url, timeout=5)
        try:
            if res.status_code == 200:
                api_data = res.json()['data'][0]
                proxies = {
                    'http': 'http://{}:{}'.format(api_data['ip'], api_data['port']),
                    'https': 'http://{}:{}'.format(api_data['ip'], api_data['port']),
                }
                print(proxies)
                return proxies
            else:
                print('獲取失敗')
        except:
            print('獲取失敗')

4.2 while循環翻頁

while循環進行翻頁,評論最大頁數是99頁,99頁之後就break跳出while循環:

 def getPLPage(self):
        while True:
            # 翻頁關鍵payload參數賦值
            self.post_data["pageNumber"]= self.page,
            self.post_data["reftag"] = f"cm_cr_getr_d_paging_btm_next_{self.page}",
            self.post_data["scope"] = f"reviewsAjax{self.page}",
            # 翻頁鏈接賦值
            spiderurl = f'https://www.amazon.it/hz/reviews-render/ajax/reviews/get/ref=cm_cr_getr_d_paging_btm_next_{self.page}'
            res = self.getRes(spiderurl,self.headers,'',self.post_data,'POST',check)#自己封裝的請求方法
            if res:
                res = res.content.decode('utf-8')
                # 返回值字符串處理
                contents = res.split('&&&')
                for content in contents:
                    infos = content.split('","')
                    info = infos[-1].replace('"]','').replace('\\n','').replace('\\','')
                    # 評論內容判斷
                    if 'data-hook="review"' in info:
                        sel = Selector(text=info)
                        data = {}
                        data['username'] = sel.xpath('//span[@class="a-profile-name"]/text()').extract_first() #用戶名
                        data['point'] = sel.xpath('//span[@class="a-icon-alt"]/text()').extract_first() #評分
                        data['date'] = sel.xpath('//span[@data-hook="review-date"]/text()').extract_first() #日期地址
                        data['review'] = sel.xpath('//span[@data-hook="review-title"]/span/text()').extract_first() #評價標題
                        data['detail'] = sel.xpath('//span[@data-hook="review-body"]').extract_first() #評價內容
                        image = sel.xpath('div[@class="review-image-tile-section"]').extract_first()
                        data['image'] = image if image else "not image" #圖片
                        print(data)
            if self.page <= 99:
                print('Next Page')
                self.page += 1
            else:
                break

最後的整合代碼:

# coding=utf-8
import requests
from scrapy import Selector
 
class getReview():
    page = 1
    headers = {
        'authority': 'www.amazon.it',
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36",
    }
    post_data = {
        "sortBy": "recent",
        "reviewerType": "all_reviews",
        "formatType": "",
        "mediaType": "",
        "filterByStar": "",
        "filterByLanguage": "",
        "filterByKeyword": "",
        "shouldAppend": "undefined",
        "deviceType": "desktop",
        "canShowIntHeader": "undefined",
        "pageSize": "10",
        "asin": "B08GHGTGQ2",
    #post_data中asin參數目前寫死在
    #"https://www.amazon.it/product-reviews/B08GHGTGQ2?ie=UTF8&pageNumber=1&reviewerType=all_reviews&pageSize=10&sortBy=recent"
    #這個鏈接裡,不排除asin值變化的可能,如要獲取get請求即可
    def getPLPage(self):
        while True:
            # 翻頁關鍵payload參數賦值
            self.post_data["pageNumber"]= self.page,
            self.post_data["reftag"] = f"cm_cr_getr_d_paging_btm_next_{self.page}",
            self.post_data["scope"] = f"reviewsAjax{self.page}",
            # 翻頁鏈接賦值
            spiderurl = f'https://www.amazon.it/hz/reviews-render/ajax/reviews/get/ref=cm_cr_getr_d_paging_btm_next_{self.page}'
            res = self.getRes(spiderurl,self.headers,'',self.post_data,'POST',check)#自己封裝的請求方法
            if res:
                res = res.content.decode('utf-8')
                # 返回值字符串處理
                contents = res.split('&&&')
                for content in contents:
                    infos = content.split('","')
                    info = infos[-1].replace('"]','').replace('\\n','').replace('\\','')
                    # 評論內容判斷
                    if 'data-hook="review"' in info:
                        sel = Selector(text=info)
                        data = {}
                        data['username'] = sel.xpath('//span[@class="a-profile-name"]/text()').extract_first() #用戶名
                        data['point'] = sel.xpath('//span[@class="a-icon-alt"]/text()').extract_first() #評分
                        data['date'] = sel.xpath('//span[@data-hook="review-date"]/text()').extract_first() #日期地址
                        data['review'] = sel.xpath('//span[@data-hook="review-title"]/span/text()').extract_first() #評價標題
                        data['detail'] = sel.xpath('//span[@data-hook="review-body"]').extract_first() #評價內容
                        image = sel.xpath('div[@class="review-image-tile-section"]').extract_first()
                        data['image'] = image if image else "not image" #圖片
                        print(data)
            if self.page <= 99:
                print('Next Page')
                self.page += 1
            else:
                break
    # api獲取ip
    def getApiIp(self):
        # 獲取且僅獲取一個ip------意大利
        api_url = '獲取代理地址'
        res = requests.get(api_url, timeout=5)
        try:
            if res.status_code == 200:
                api_data = res.json()['data'][0]
                proxies = {
                    'http': 'http://{}:{}'.format(api_data['ip'], api_data['port']),
                    'https': 'http://{}:{}'.format(api_data['ip'], api_data['port']),
                }
                print(proxies)
                return proxies
                print('獲取失敗')
        except:
            print('獲取失敗')
    #專門發送請求的方法,代理請求三次,三次失敗返回錯誤
    def getRes(self,url,headers,proxies,post_data,method):
        if proxies:
            for i in range(3):
                try:
                    # 傳代理的post請求
                    if method == 'POST':
                        res = requests.post(url,headers=headers,data=post_data,proxies=proxies)
                    # 傳代理的get請求
                    else:
                        res = requests.get(url, headers=headers,proxies=proxies)
                    if res:
                        return res
                except:
                    print(f'第{i+1}次請求出錯')
                else:
                    return None
        else:
                proxies = self.getApiIp()
                    # 請求代理的post請求
                        res = requests.post(url, headers=headers, data=post_data, proxies=proxies)
                    # 請求代理的get請求
                        res = requests.get(url, headers=headers, proxies=proxies)
                    print(f"第{i+1}次請求出錯")
if __name__ == '__main__':
    getReview().getPLPage()

總結

本次的亞馬遜評論獲取就是兩個坑,一是評論信息通過的XHR請求方式,二是評論信息的處理。分析之後這次的數據獲取還是非常簡單的,找到正確的請求方式,穩定的IP代理讓你事半功倍,找到信息的共同點進行處理,問題就迎刃而解瞭。

到此這篇關於基於Python獲取亞馬遜的評論的文章就介紹到這瞭,更多相關Python亞馬遜的評論內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: