在爬取工作之前,我们需要先做一些准备工作:
做完准备工作之后,就可以开始分析要爬取的网页信息了。分析过程中,发现淘宝对搜索进行了限制,只有登陆账号之后才能进行搜索。一开始我想通过模拟输入账号密码进行登录操作,结果发现淘宝添加了滑块验证,而且使用selenium无法模拟滑块验证。实验了一些方法后,决定使用保存cookie的方式来绕过登陆的限制。
登陆界面的网址是https://login.taobao.com/member/login.jhtml,登陆成功则会跳转回淘宝主页https://www.taobao.com/,所以可以依此判断登陆是否成功。
代码实现如下:
url = "https://www.taobao.com/"
browser.get("https://login.taobao.com/member/login.jhtml")
while True:
time.sleep(5)
while browser.current_url == url:
tbCookies = browser.get_cookies()
得到cookies后发现是以dict组成的list来存储的,我们主要需要的是name和value两个参数:
[{'domain': '.taobao.com', 'expiry': 1566657999, 'httpOnly': False, 'name': 'isg', 'path': '/', 'secure':False,'value':'BHBwphRF2ADZXIQE5QdBaN_xQTgCEX_Oib2H0WrBPEueJRDPEskkk8aXeSxFtQzb'},...{...}]
为了以后能继续使用,采用pickle将cookies保存到文件中:
cookies = {}
for item in tbCookies:
cookies[item['name']] = item['value']
with open('taobaoCookies.txt', 'wb') as f:
pickle.dump(cookies, f)
这样我们就能从文件中直接获取到存储到cookies,不需要每次都登陆了(ps:这里有点问题,就是每天重新开启爬取时都需要扫码登录一次后才能使用cookies登陆,目前还不知道如何解决)
接下来就是进行搜索对商品信息进行爬取了,先将搜索到的第一页内容进行爬取,需要先打开淘宝首页后添加存储的cookies,再进行爬取工作:
browser.get("https://www.taobao.com/")
for cookie in cookies:
browser.add_cookie({
'domain': '.taobao.com',
'name': cookie,
'value': cookies[cookie],
'path': '/',
'expires': None
})
等到搜索框和提交按钮加载完成后,即可模拟输入商品进行搜索的操作:
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
submit = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'btn-search')))
input.send_keys(KEYWORD)
submit.click()
接下来就是获取商品的详细信息了,这里采用了Pyquery对数据进行解析:
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item'))) #等待商品信息加载出来
html = browser.page_source
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
for item in items:
result = {
'image': item.find('.pic .img').attr('src'),
'price': item.find('.price').text(),
'dealcount': item.find('.deal-cnt').text()[:-3],
'title': item.find('.title').text(),
'shop': item.find('.shop').text(),
'location': item.find('.location').text()
}
获取到第一页数据之后,就需要进行翻页操作获取后面页数的数据,翻页的方式有几种,这里我采用的是输入页数点击跳转来进行翻页:
page = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input')))
page.clear() #清空页码输入框
page.send_keys(str(page_number))
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit')))
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_number))) #确认要跳转的页码是正确的
不同页的数据获取方式与第一页类似,这里就不重复说明了。
爬取下来的数据使用mongoDB进行存储,使用mongoDB前先写好配置文件定义好mongoDB的服务地址、数据库名和表名:
MONGO_URL = 'localhost'
MONGO_DB = 'taobao'
MONGO_TABLE = 'product'
然后就可以开启mongoDB客户端对数据库表进行操作了:
client = pymongo.MongoClient(MONGO_URL)
db = client[MONGO_DB]
try:
if db[MONGO_TABLE].insert_one(result):
print('保存到mongoDB成功')
except Exception:
print('保存到mongoDB失败')
这个练习我主要使用了单进程进行爬取,有时间再看看换成多进程爬取。
完整的代码如下:
import pickle
import os
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from pyquery import PyQuery as pq
from config import *
import pymongo
chrome_options = Options()
chrome_options.add_argument('user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36')
browser = webdriver.Chrome('@chromedriver所在路径', options = chrome_options)
wait = WebDriverWait(browser, 10)
url = "https://www.taobao.com/"
browser.set_window_size(1400, 900) #设置浏览器大小
client = pymongo.MongoClient(MONGO_URL) #创建mongoDB客户端
db = client[MONGO_DB]
def getTaobaoCookies():
browser.get("https://login.taobao.com/member/login.jhtml")
while True:
while browser.current_url == url:
tbCookies = browser.get_cookies()
print(tbCookies)
browser.quit()
cookies = {}
for item in tbCookies:
cookies[item['name']] = item['value']
with open('taobaoCookies.txt','wb') as f:
pickle.dump(cookies, f)
return cookies
def read_to_cookies():
if os.path.exists('taobaoCookies.txt'):
with open('taobaoCookies.txt', 'rb') as f:
cookies = pickle.loads(f.read())
else:
cookies = getTaobaoCookies()
return cookies
def search(cookies):
browser.get(url)
for cookie in cookies:
browser.add_cookie({
'domain': '.taobao.com',
'name': cookie,
'value': cookies[cookie],
'path': '/',
'expires': None
})
try:
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
submit = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'btn-search'))) #判断搜索按钮是否可点击
input.send_keys(KEYWORD) #KEYWORD为搜索的关键词
submit.click()
total_page = int(wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'total'))).text[2:5]) #获取总页数
get_product_info()
return total_page
except TimeoutException:
return search(cookies)
def next_page(page_number):
print('翻到第%d页' % page_number)
try:
page = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input')))
page.clear()
page.send_keys(str(page_number))
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit')))
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_number)))
get_product_info()
except TimeoutException:
return next_page(page_number)
def get_product_info():
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
html = browser.page_source #获取页面源代码
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
for item in items:
result = {
'image': item.find('.pic .img').attr('src'),
'price': item.find('.price').text(),
'dealcount': item.find('.deal-cnt').text()[:-3],
'title': item.find('.title').text(),
'shop': item.find('.shop').text(),
'location': item.find('.location').text()
}
save_to_mongo(result)
def save_to_mongo(result):
try:
if db[MONGO_TABLE].insert_one(result): #insert过时,采用insert_one
print('保存到mongoDB成功')
except Exception:
print('保存到mongoDB失败')
if __name__ == '__main__':
cookies = read_to_cookies()
try:
#获取总页数,并获取第一页数据
total_page = search(cookies)
for i in range(2, total_page + 1):
next_page(i)
finally:
browser.close()