Spider_jdSeacrh

作者: GHope | 来源:发表于2018-11-05 16:47 被阅读36次

本次爬取的内容为京东的搜索功能。通过selenium利用驱动启动浏览器,并输入搜索内容,并模拟切换页面、滚动页面等操作抓取搜索结果。保存搜索商品结果的标识、描述、价格、商家、图片地址及商品链接到本地数据库中。

爬取过程

首先设置浏览器(无头浏览器可不设——设置目的为了提高效率及尽可能少的占用内存) -- 使用驱动启动浏览器 -- 设置启动的浏览器的界面大小及等待页面内容加载的时间 -- 通过多次观察发现京东的搜索结果均为100页 -- 主函数中通过循环生成每次填入的页码 -- 将页码传递给模拟切换页面的函数 -- 模拟切换页面的函数判断页码是否为一,若为一则向页面写入经过编码的搜索内容到请求地址中,若不为一则先得到页码输入框和确认按钮,之后清空页码输入框(避免输入页码追加到原有页码之后)输入得到的页码,点击确认按钮 -- 使用循环分六次滚动刷新页面(避免页面内容缺省太多) -- 返回当前页面内容 -- 解析页面内容(首先将所有拿到的li标签强制转换为一个list,通过循环该列表拿到单个商品的li标签。再使用.匹配li标签中的内容,存为dict形式后添加到商品list中,便于之后插入到数据库中。) -- 连接数据库保存数据 -- 抛商标标识唯一引起的异常

import time
import random
import pymysql
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 urllib.parse import quote
from lxml import etree

# 无头浏览器
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
# 启动浏览器
browser = webdriver.Chrome(chrome_options=chrome_options)

# 指定自启浏览器界面大小
browser.set_window_size(1400, 700)
# 显式等待  针对整个节点的等待
wait = WebDriverWait(browser, 3)
# 设置关键字
KEYWORD = '古风'


# 隐式等待(不推荐使用)
# browser.implicitly_wait(3)

# 模拟切换页面
def get_page(page):
    if page == 1:
        # 第一次访问的地址
        url = 'https://search.jd.com/Search?keyword=%s&enc=utf-8' % quote(KEYWORD)
        # 访问地址
        browser.get(url)
    if page > 1:
        # 获取页数输入框
        input = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, '#J_bottomPage input.input-txt')))
        # 获取确认按钮
        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_bottomPage a.btn.btn-default')))
        # 清空页数输入框
        input.clear()
        # 将目标页数填入到页数输入框
        input.send_keys(page)
        # 点击确认按钮
        submit.click()
        wait.until(
            EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#J_bottomPage a.curr'), str(page)))
        wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_goodsList')))
    # 随机等待时间
    t = random.randint(0, 9)
    # 分六次滚动页面
    for i in range(6):
        str_js = 'var step = document.body.scrollHeight/6;window.scrollTo(0,step*%d)' % (i + 1)
        browser.execute_script(str_js)
        time.sleep(t)
    # 得到访问的页面内容
    page_source = browser.page_source
    return page_source


# 解析获取到的页面
def parse_page(page_source):
    # 创建xpath解析对象
    etree_html = etree.HTML(page_source)
    # print(page_source)
    # print(type(etree_html))
    # 得到单个商品(解决一个商品单个属性中多个信息的选择)
    goods_list = list(etree_html.xpath('//div[@id="J_goodsList"]/ul/li'))
    # print(len(goods_list))
    goods_db = []
    for goods in goods_list:
        item = {}
        # 解析标识
        goods_sku = goods.xpath('./@data-sku')
        # print(goods_sku[0])
        item['sku'] = goods_sku[0]
        # 解析描述(.表示当前目录)
        goods_title = goods.xpath('.//div[@class="p-name p-name-type-2"]/a/em/text()')
        # print(goods)
        # print(goods_title)
        title = ''
        for i in goods_title:
            title += i
        # print(title)
        # print(len(goods_title))
        item['title'] = title.replace(' ', '')
        # 解析价格
        goods_price = goods.xpath('.//div[@class="p-price"]/strong/i/text()')
        # print(goods_price[0])
        item['price'] = goods_price[0]
        # 解析商家
        goods_shop = goods.xpath('.//div[@class="p-shop"]/span/a/@title')
        # print(goods_shop[0])
        item['shop'] = goods_shop[0]
        # 解析评价数量
        goods_commit = goods.xpath('.//div[@class="p-commit"]/strong/a/text()')
        # print(goods_commit[0])
        item['commit'] = goods_commit[0]
        # 解析图片地址(部分图片加载不到,设置重复更新后多次爬取)
        goods_img = goods.xpath('.//div[@class="p-img"]/a/img/@src')
        # print(goods_img)
        item['img'] = goods_img
        if goods_img:
            item['img'] = goods_img[0]
        else:
            item['img'] = ''
        # 解析商品链接
        goods_link = goods.xpath('.//div[@class="p-img"]/a/@href')
        # print(goods_link)
        item['link'] = goods_link[0]
        # 将解析好的单品信息加入返回结果中
        goods_db.append(item)
    return goods_db


def join_MySql(goods_db):
    # 设置数据库参数
    host = '127.0.0.1'
    user = 'root'
    password = 'root'
    port = 3306
    db = 'jdSeacrh'
    db = pymysql.connect(host=host, user=user, password=password, port=port, db=db)
    # 连接数据库
    cursor = db.cursor()
    for i in range(len(goods_db)):
        sql = "INSERT INTO seacrh_gufeng(sku,title,price,shop,commit,img,link)" \
              " VALUES('{}','{}','{}','{}','{}','{}','{}')".format(goods_db[i]['sku'], goods_db[i]['title'],
                                                                   goods_db[i]['price'], goods_db[i]['shop'],
                                                                   goods_db[i]['commit'],
                                                                   goods_db[i]['img'], goods_db[i]['link'])
        # print(sql)
        try:
            cursor.execute(sql)
            db.commit()
        except:
            print('元素已存在')
    db.close()


def main():
    for page in range(100):
        # 动态增加页数
        page_source = get_page(page + 1)
        # 解析页面内容
        goods_db = parse_page(page_source)
        join_MySql(goods_db)


if __name__ == '__main__':
    main()

总结:

京东这一块最麻烦的是解析页面,存的时候总是数据格式出错。也许是因为存储的是MySQL的原因吧!商品描述是em标签下被span分开的一个或多个字符串,导致解析难度提升!还有图片地址的问题到现在还没想到什么方法完美解决,每次加载的时候只有少量的图片地址能够被加载出来。知道应该多次访问,存图片的时候判断该信息是否存在,但又好像和唯一索引冲突。。。很迷...

GitHub地址

相关文章

  • Spider_jdSeacrh

    本次爬取的内容为京东的搜索功能。通过selenium利用驱动启动浏览器,并输入搜索内容,并模拟切换页面、滚动页面等...

网友评论

本文标题:Spider_jdSeacrh

本文链接:https://www.haomeiwen.com/subject/gcgctqtx.html