python爬蟲獲取天貓店鋪信息
爬取需求
在天貓搜索一個關鍵詞,然後抓取這個關鍵詞下的相關店鋪,由於taobao的反爬策略,只能爬取到第十頁大概200個店鋪的信息。
效果預覽
最終爬取的數據用excel保存,部分數據如下
環境準備
-
python3
-
合適版本的chromedriver 參考https://blog.csdn.net/BinGISer/article/details/88559532
-
第三方庫:selenium、pandas、BeautifulSoup(pip install bs4)
-
綁定了taobao賬號的微博賬號與密碼
-
電腦與網絡
代碼
# coding=utf-8
# @Time : 2020/6/11 19:51
# @Author : mxz
# @File : main.py
# @Software: PyCharm
import re
import time
import pandas as pd
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
from fateadm_api import FateadmApi
PRED_TYPE= "30500"
class TmallShopSpider(object):
def __init__(self, username, password, chromedriver_path):
self.url = 'https://login.taobao.com/member/login.jhtml' # 淘寶登錄地址
self.username = username # 接收傳入的 賬號
self.password = password # 接收傳入的 密碼
options = webdriver.ChromeOptions()
options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2}) # 不加載圖片,加快訪問速度
options.add_experimental_option('excludeSwitches', ['enable-automation']) # 設置爲開發者模式,防止被各大網站識別出來使用了Selenium
self.browser = webdriver.Chrome(executable_path=chromedriver_path, chrome_options=options) # 接收傳入的 chromedriver地址 和設置好的 options
self.browser.maximize_window() # 設置窗口最大化
self.wait = WebDriverWait(self.browser, 10) # 設置一個智能等待爲10秒
def login(self,on_login_web):
if not on_login_web:
self.browser.get(self.url)
# username_password_button = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.login-box.no-longlogin.module-quick > .hd > .login-switch'))) # 用css選擇器選擇 用賬號密碼登錄按鈕
# username_password_button.click() # 點擊 用賬號密碼登錄按鈕
weibo_button = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.weibo-login'))) # 用css選擇器選擇 用微博登錄按鈕
weibo_button.click() # 點擊 用微博登錄按鈕
input_username = self.wait.until(EC.presence_of_element_located((By.XPATH, '//input[@name="username"]'))) # 用xpath選擇器選擇 賬號框
input_username.send_keys(self.username) # 輸入 賬號
input_password = self.wait.until(EC.presence_of_element_located((By.XPATH, '//input[@name="password"]'))) # 用xpath選擇器選擇 密碼框
input_password.send_keys(self.password) # 輸入 密碼
time.sleep(3)
login_button = self.wait.until(EC.presence_of_element_located((By.XPATH, '//span[text()="登錄"]'))) # 用xpath選擇器選擇 登錄按鈕
login_button.click() # 點擊 登錄按鈕
def getPageTotal(self):
# 存在登錄後進入滑動驗證碼頁面的情況,此時無法獲取頁數,做法是回退一步再次登錄
try:
page_total = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.ui-page-skip > form'))) # 用css選擇器選擇 商品列表頁 總頁數框
page_total = page_total.text
page_total = re.match('.*?(\d+).*', page_total).group(1) # 清洗
return page_total
except:
if self.sliderVerification():
# self.browser.back()
self.login(on_login_web=True)
return self.getPageTotal()
def dropDown(self):
# 模擬人類 向下滑動瀏覽(下拉有加速度)
for i in range(1, 52):
drop_down = "var q=document.documentElement.scrollTop=" + str(i*100)
self.browser.execute_script(drop_down)
time.sleep(0.01)
if i == 5:
time.sleep(0.7)
if i == 15:
time.sleep(0.5)
if i == 29:
time.sleep(0.3)
if i == 44:
time.sleep(0.1)
# 直接下拉到最底部
# drop_down = "var q=document.documentElement.scrollTop=10000"
# self.browser.execute_script(drop_down)
def nextPage(self):
# 獲取 下一頁的按鈕 並 點擊
next_page_submit = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.ui-page-next')))
next_page_submit.click()
def sliderVerification(self):
# 滑塊驗證有滑動,但驗證失敗,失敗後人工滑動驗證也會失敗
# 每次翻頁後 檢測是否有 滑塊驗證
try:
slider_button = WebDriverWait(self.browser, 5, 0.5).until(EC.presence_of_element_located((By.ID, 'nc_1_n1z')))
# action = ActionChains(self.browser)
# action.click_and_hold(slider_button).perform()
# action.reset_actions()
# # 模擬人類 向左拖動滑塊(拖動有加速度)
# for i in range(100):
# action.move_by_offset(i*1, 0).perform()
# time.sleep(0.01)
# action.reset_actions()
# 嘗試出現驗證碼後返回上一頁
self.browser.back()
return True
except:
print('沒有檢測到滑塊驗證碼')
return False
def crawlShops(self, category):
# self.login(on_login_web=False)
self.browser.get('https://list.tmall.com/search_product.htm?q={0}'.format(category)) # 天貓商品列表頁地址,format()裏面輸入要爬取的類目
shop_button=self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.fType-w ')))
shop_button.click()
self.login(on_login_web=True)
page_total = self.getPageTotal() # 獲取 商品列表頁 總頁數
print(''.join(['爬取的類目一共有:', page_total, '頁']))
shop_data=[]
for page in range(2, int(page_total)): # 遍歷 全部 商品列表頁
page_frame = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.ui-page-skipTo'))) # 獲取 當前頁數框
page_now = page_frame.get_attribute('value') # 獲取 當前頁數
print(''.join(['當前頁數:', page_now, ' ', '總頁數:', page_total]))
html = self.browser.page_source # 獲取 當前頁面的 源代碼
soup=BeautifulSoup(html,'lxml')
shop_list=soup.find_all(class_="shopHeader-info")
for shop in shop_list:
one_data={}
one_data['種類']=category
one_data["店名"]=shop.find(class_="sHi-title").text
one_data["鏈接"]="https://list.tmall.com/"+shop.find(class_="sHi-title")['href']
one_data["頁數"]=page_now
shop_data.append(one_data)
pd.DataFrame(shop_data).to_excel(category+".xlsx")
self.dropDown() # 執行 下拉動作
self.nextPage() # 執行 按下一頁按鈕動作
time.sleep(1)
self.sliderVerification() # 檢測是否有 滑塊驗證
time.sleep(1)
self.checkNotFoundWebPage()
time.sleep(1)
pd.DataFrame(shop_data).to_excel(category+".xlsx")
def checkNotFoundWebPage(self):
# 翻頁時有時會出現無法找到相關店鋪的頁面,但其實還不是最後一頁店鋪,
# 此時按返回上一步再次進入下一頁
try:
search_tip = WebDriverWait(self.browser, 5, 0.5).until(EC.presence_of_element_located((By.CSS_SELECTOR, '.searchTip-kw')))
# 嘗試出現驗證碼後返回上一頁
self.browser.back()
return True
except:
print('沒有檢測到無法搜索店鋪的頁面')
return False
username = '' # 你的 微博賬號
password = '' # 你的 微博密碼
chromedriver_path = 'chromedriver.exe' # 你的 selenium驅動 存放地址
category = "職業裝" # 你要爬取的 搜索關鍵詞
if __name__ == '__main__':
a = TmallShopSpider(username, password, chromedriver_path)
a.crawlShops(category)
難點
代碼裏面已經有註釋,一些難點與未解決的點列舉如下
-
sliderVerification用於處理出現滑動驗證碼的情況,在翻頁查找靠後的店鋪時(大概在第十頁開始頻繁出現),註釋裏面有模擬人工滑動驗證的做法,但滑動後驗證不成功,甚至在程序終止後人工去滑動也會一直失敗,所以我選擇了後退一步,回到上個頁面然後繼續點下一頁。經過驗證,這會導致上一頁數據被重新爬取,我選擇了最後在excel裏刪除重複項,讀者可以選擇在代碼裏去重,下面是滑動驗證的界面
-
有時候還會遇到出現無法搜到相關店鋪的頁面,如下圖
但其實是能搜到的,做法跟上面一樣,返回上一個頁面,繼續點下一頁,同樣也會造成數據重複,好處就是程序不容易終止,多試幾次就又能找到店鋪了,這應該也是taobao的一個反爬策略
總結
如果需要爬取的店鋪數量不多的話上述代碼可以解決,如果需要高一個數量級的店鋪就需要想辦法破解那個滑動驗證碼,如果已經有好的辦法的話希望能一起討論。