1. 程式人生 > 其它 >爬蟲實戰三:爬淘寶商品資訊

爬蟲實戰三:爬淘寶商品資訊

目錄

爬淘寶商品資料

免責宣告:本文所記錄的技術手段及實現過程,僅作為爬蟲技術學習使用,不對任何人完全或部分地依據本文的全部或部分內容從事的任何事情和因其任何作為或不作為造成的後果承擔任何責任

一、 簡介

於近年來淘寶的反爬措施逐漸完善,爬取難度變大,在爬取時必須要登入之後才能檢視相關的商品資訊,淘寶資料是通過動態載入的方式顯示的,所以本文使用selenium模擬瀏覽器操作爬取商品頁詳情資訊 , 需要提取安裝和selenuim和瀏覽器驅動chromedriver

1、 環境準備

使用的第三方庫

async-generator==1.10
attrs==21.4.0
beautifulsoup4==4.10.0
bs4==0.0.1
certifi==2021.10.8
cffi==1.15.0
charset-normalizer==2.0.12
cryptography==36.0.1
cssselect==1.1.0
fake-useragent==0.1.11
h11==0.13.0
HTMLParser==0.0.2
idna==3.3
logger==1.4
lxml==4.8.0
outcome==1.1.0
pinyin==0.4.0
pycparser==2.21
pyOpenSSL==22.0.0
pyquery==1.4.3
PySocks==1.7.1
requests==2.27.1
selenium==4.1.2
sniffio==1.2.0
sortedcontainers==2.4.0
soupsieve==2.3.1
trio==0.20.0
trio-websocket==0.9.2
urllib3==1.26.8
wsproto==1.1.0
xpinyin==0.7.6

2、 頁面分析

通過分析淘寶的頁面的資料,可以知道淘寶頁面的資料是通過 JS 動態加載出來的,再分析頁面原始碼,可以發現每頁的商品資料儲存在 p_page_config這個變數裡面

二、 程式碼

1、 使用 selenium 模擬登入

該檔名為 Login.py

from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.by import By
from fake_useragent import UserAgent
from time import sleep


# 獲取登入狀態
class Login:
    def __init__(self):  # 全部設定為私有屬性,封裝類
        self.driver = None
        self.__init_browser()  # 初始化瀏覽器
        self.__wait = WebDriverWait(self.driver, 180)  # 顯示等待
        self.__main()  # 該方法也可以在外部呼叫

    def __init_browser(self) -> "初始化 瀏覽器":
        __options = ChromeOptions()
        __options.add_experimental_option('excludeSwitcher',
                                          ['enable-automation'])  # 設定開發者模式啟動,該模式下webdriver屬性為正常值
        __option = ChromeOptions()
        __option.add_argument(f'user-agent={UserAgent().random}')  # 設定請求頭
        # __option.add_argument(
        #     r'--user-data-dir=C:\Users\35005\AppData\Local\Google\Chrome\User Data\Default')  # 載入自己的資料
        self.driver = Chrome(chrome_options=__option, options=__options)  # 新增到瀏覽器中
        self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """
                Object.defineProperty(navigator, 'webdriver', {
                    get: () => undefined
                })
            """
        })  # 避免淘寶滑塊驗證

    def __login(self) -> "登 錄":
        self.driver.maximize_window()  # 最大化視窗
        self.driver.get("https://login.taobao.com/member/login.jhtml")  # 請求登入網頁
        self.driver.find_element(By.XPATH, "//div[@id='login']/div[1]/i").click()  # 二維碼登入
        self.__wait.until(expected_conditions.presence_of_element_located((By.ID, "q")))  # 等待二維碼登入,知道搜尋框出現
        # cookie = self.driver.execute_script("return document.cookie")  # 呼叫 JS 程式碼,獲得cookie
        # self.driver.close()  # 關閉瀏覽器
        # return cookie

    def __main(self):
        self.__login()  # 呼叫介面
        sleep(5)  # 停止 5 秒鐘
        # cookie = self.__login()
        # with open("../Config/cookie.pickle", "wb") as f:
        #     pickle.dump(cookie, f)  # 將資料儲存到二進位制檔案中

if __name__ == '__main__':
    driver = Login()  # 直接呼叫 main 方法

2、 解析頁面資料

import re, json
from ConfiCode.Login import Login  # 登入淘寶
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from threading import Thread
from time import sleep, ctime


class SpiderGoods:

    def __init__(self, u) -> "初始化 物件":
        self.__driver = None  # 接收瀏覽器物件
        self.__url = u  # 接收 url
        self.__all_lis = []  # 存放所有字典型別資料
        self.__file = open("./Config/log.txt", "a", encoding="utf-8")

    def __verify(self) -> "滑塊 問題":
        while True:
            try:
                self.__driver.find_element(By.XPATH, "//*[@id='nc_1__scale_text']/span")  # 如果找到滑塊
                self.__file.write(f"出現滑塊,正在處理!{ctime()}\n")
                self.__file.flush()
                sleep(2)
                print("出現滑塊,正在處理!")
                ActionChains(self.__driver).click_and_hold().drag_and_drop_by_offset(260, 0).release().perform()  # 拖動滑塊
            except:
                sleep(3)  # 如果沒有找到滑塊

    def __get_driver(self) -> "得到 瀏覽器物件":
        l = Login()  # 得到瀏覽器物件
        self.__driver = l.driver

    def __get_page_source(self) -> "獲取 資料":
        self.__get_driver()
        self.__file.write(f"登入成功!{ctime()}\n")
        self.__file.flush()
        sleep(2)
        print("登入成功!")
        for i in range(100):  # 淘寶一共有 100 頁
            every_page = []  # 儲存每頁的資料
            url = f"{self.__url}&s={44 * i}"  # 拼接 url
            self.__file.write(f"開始爬取第{i + 1}頁!{ctime()}\n")
            self.__file.flush()
            sleep(2)
            print(f"開始爬取第{i + 1}頁")
            self.__driver.get(url)  # 傳送請求
            sleep(10)  # 停止 10 秒鐘
            try:
                cot = re.search("g_page_config = {(?P<p_page_source>.*?)};",
                                self.__driver.page_source).group("p_page_source")  # 得到儲存資料的頁面
            except:
                continue
            cot = "{" + cot + "}"  # 拼接成 JSON 字串
            cot_dic = json.loads(cot)  # 轉換為字典
            data_lis = cot_dic["mods"]["itemlist"]["data"]["auctions"]  # 得到儲存資料的列表
            for j in data_lis:
                # 標題
                try:
                    title = j["raw_title"]
                except:
                    title = "暫無"

                # 進入詳情頁的 url
                try:
                    detail_url = j["nid"]
                    detail_url = f"https://item.taobao.com/item.htm?&id={detail_url}"
                except:
                    detail_url = "暫無"

                # 圖片 url
                try:
                    pic_url = j["pic_url"]
                    pic_url = f"https:{pic_url}"
                except:
                    pic_url = "暫無"

                # 價格
                try:
                    price = j["view_price"]
                except:
                    price = "-1"

                # 地址
                try:
                    location = j["item_loc"]
                except:
                    location = "暫無"

                # 銷量
                try:
                    sales = j["view_sales"]
                except:
                    sales = "暫無"

                # 店鋪
                try:
                    nick = j["nick"]
                except:
                    nick = "暫無"

                # 評論數量
                try:
                    comment = j["comment_count"]
                except:
                    comment = "-1"

                v_dic = {"標題": title, "詳情頁url": detail_url, "圖片url": pic_url,
                         "最低價格": price, "發貨地址": location, "銷量": sales, "店鋪名稱": nick, "評論數量": comment}  # 儲存資料
                # print(v_dic)
                every_page.append(v_dic)
            p_dic = {f"第{i + 1}頁": every_page}  # 將頁面內容新增的列表中
            self.__file.write(f"獲取完第{i + 1}頁!{ctime()}\n")
            self.__file.flush()
            sleep(2)
            print(f"獲取完第{i + 1}頁")
            self.__all_lis.append(p_dic)  # 把頁面資料新增到列表中
            # print(self.__all_lis)
            sleep(5)  # 停止 3 秒鐘

    def __save_to_json(self) -> "儲存 資料":
        self.__get_page_source()
        name = self.__url.split("=")[-1]
        with open(f"./Source/{name}.json", "w", encoding="utf-8") as f:
            json.dump(self.__all_lis, f, indent=2, ensure_ascii=False)

    def main(self) -> "程式 入口":
        # 開啟執行緒,無限判斷是否有滑塊
        t1 = Thread(target=self.__verify)
        t1.start()
        t2 = Thread(target=self.__save_to_json)
        t2.start()
        t1.join()
        t2.join()
        self.__driver.close()  # 關閉驅動
        self.__file.write(f"爬取完成!{ctime()}\n")
        self.__file.flush()
        sleep(2)
        print("爬取完成!")
        sleep(5)
        self.__file.truncate()
        self.__file.close()


if __name__ == '__main__':
    name = input("請輸入關鍵詞:\n")
    s = SpiderGoods(f"https://s.taobao.com/search?q={name}")
    s.main()

三、 專案完整程式碼

在 【https://download.csdn.net/download/qq_62789540/83519171】不需要積分哦!!!

本文來自部落格園,作者:A-L-Kun,轉載請註明原文連結:https://www.cnblogs.com/liuzhongkun/p/15969668.html