爬淘寶商品數據
免責聲明:本文所記錄的技術手段及實現過程,僅作為爬蟲技術學習使用,不對任何人完全或部分地依據本文的全部或部分內容從事的任何事情和因其任何作為或不作為造成的后果承擔任何責任
一、 簡介
於近年來淘寶的反爬措施逐漸完善,爬取難度變大,在爬取時必須要登錄之后才能查看相關的商品信息,淘寶數據是通過動態加載的方式顯示的,所以本文使用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】不需要積分哦!!!