爬取淘宝商品信息

学习了爬虫之后,做了一些实战练习。今天记录下练习爬取淘宝商品信息的过程,希望对大家会有点帮助。如果有什么错误的地方,还望多多指点。

在爬取工作之前,我们需要先做一些准备工作:

  1. 因为在这个练习中,我使用的是selenium+chromedriver进行爬取的,所以需要安装与chrome浏览器版本相对应的chromedriver,下载地址为http://chromedriver.storage.googleapis.com/index.html
  2. 数据存储使用的是MongoDB,所以需要安装mongoDB

做完准备工作之后,就可以开始分析要爬取的网页信息了。分析过程中,发现淘宝对搜索进行了限制,只有登陆账号之后才能进行搜索。一开始我想通过模拟输入账号密码进行登录操作,结果发现淘宝添加了滑块验证,而且使用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()

你可能感兴趣的:(爬虫)