继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Spider_jdSeacrh

慕标5832272
关注TA
已关注
手记 1071
粉丝 228
获赞 996

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

爬取过程

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

import timeimport randomimport pymysqlfrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom urllib.parse import quotefrom 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_dbdef 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分开的一个或多个字符串,导致解析难度提升!还有图片地址的问题到现在还没想到什么方法完美解决,每次加载的时候只有少量的图片地址能够被加载出来。知道应该多次访问,存图片的时候判断该信息是否存在,但又好像和唯一索引冲突。。。很迷...



作者:GHope
链接:https://www.jianshu.com/p/ebda022a5fef


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP