需求:通過淘寶模擬登錄打造一個關鍵詞搜索庫
'''
思路:
1. 打開瀏覽器,輸入關鍵詞搜索
2. 跳轉至登錄頁面,使用微博登錄
3. 登錄完成獲取列表頁
4. 解析數據
5. 保存數據
'''
import time
import re
import pymongo
from pyquery import PyQuery as pq
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
# 這個包是導入配置包,里面可以存放數據庫連接和關鍵詞以及登錄賬號密碼等常量
from settings import *
# 將瀏覽器設置為無頭瀏覽器
chrome_options = Options()
chrome_options.add_argument("headless")
chrome_options.add_argument("--disable-gpu")
# 打開瀏覽器
chrome = webdriver.Chrome()
# 為了保證不出錯,定義一個顯式等待變量
wait = WebDriverWait(chrome, 10)
# 連接MongoDB
client = pymongo.MongoClient(MONGO_URL)
db = client[MONGO_DB]
def search():
'''
此函數主要用來模擬登錄以及獲取第一頁數據
'''
try:
chrome.get('https://www.taobao.com/')
# 輸入關鍵字點擊搜索
input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#q")))
submit = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "#J_TSearchForm > div.search-button > button")))
input.send_keys(KEY_WORD)
time.sleep(1)
submit.click()
# 模擬登錄(用微博登錄)
login = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#login-form > div.login-blocks.sns-login-links > a.weibo-login"))).click()
chrome.find_element_by_xpath("//*[@id='pl_login_logged']/div/div[2]/div/input").send_keys(USERNAME)
time.sleep(1)
chrome.find_element_by_xpath("//*[@id='pl_login_logged']/div/div[3]/div/input").send_keys(PASSWORD)
time.sleep(1)
chrome.find_element_by_xpath("//*[@id='pl_login_logged']/div/div[7]/div[1]/a/span").click()
# 獲取總頁數
total_page = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.total")))
# 解析數據 注意:等待可以獲取到底部總頁數的時候,說明列表頁已經加載完畢,可以開始解析數據
get_product()
return total_page.text
except TimeoutError:
# 如果請求出錯,遞歸調用自身,相當於retrying
return search()
def next_page(page_num):
'''
這個函數用來請求列表頁
'''
try:
# 請求下一頁
input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > input")))
submit = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit"))
)
input.clear()
input.send_keys(page_num)
submit.click()
wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > ul > li.item.active > span"),str(page_num)))
# 解析數據
get_product()
except TimeoutError:
next_page(page_num)
def get_product():
'''
這個函數用來解析數據,解析庫可以根據自己喜好更改
'''
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
html = chrome.page_source
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
for item in items:
product = {
'image': item.find('.pic .img').attr('src'),
'price': item.find('.price').text(),
'deal': item.find('.deal-cnt').text()[:-3],
'title': item.find('.title').text().strip(),
'shop': item.find('.shop').text(),
'location': item.find('.location').text()
}
print(product)
save_to_mongo(product)
def save_to_mongo(result):
'''
保存到MongoDB
'''
try:
if db[MONGO_TABLE].insert_one(result):
print('保存到MONGODB成功', result)
except Exception:
print('保存到MONGODB失敗', result)
def main():
'''
主要爬網邏輯
'''
try:
total = search()
# 獲取總頁數
total = int(re.compile('(\d+)').search(total).group(1))
for i in range(2, total+1):
next_page(i)
except Exception:
print('出錯了')
finally:
chrome.close()
if __name__ == '__main__':
main()
以上代碼不足之處,沒有使用代理,淘寶網算是反爬比較厲害的網站,時不時會跳出來瀏覽限制(比如讓輸入驗證碼),一般都是因為同一個ip短時間內數據獲取量太快
提供三個解決方案
1. 外接打碼平台,識別驗證碼,返回輸入
2. 如果比較牛逼,可以使用深度學習圖像識別識別驗證碼輸入
3. 使用代理,這個是個人覺得比較好的解決方案,從可行性和解決問題的本質上算比較優的解決方案
配置文件內容
微博賬號和密碼(微博要和淘寶是同一個手機號哦)
USERNAME = '----------'
PASSWORD = '----------'
MongoDB配置
MONGO_URL = 'localhost'
MONGO_DB = 'taobao'
MONGO_TABLE = 'product'
關鍵詞
KEY_WORD = '美食'