[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)

 

目录

一、环境

二、简介

三、京东网页分析

1.获取商品信息入口--商品列表链接获取

2.获取商品信息入口--商品详情链接获取

3.商品详情获取

4.商品评论获取

四、代码实现

五、运行结果

六、结语


一、环境

       win10 + python 3.7 + pycharm64 + selenium

二、简介

       抓取京东商品页面信息:商品名称,售价,店铺,分类,订单信息,好评率,评论等----这里以'每周一花'为例

三、京东网页分析

       采集思路如下:

此次主要采集以下字段数据:

  • title:商品名称
  • price:售价
  • brand:品牌
  • shop_name:店名
  • weight:商品重量
  • user:适用人群
  • classify:商品分类
  • comment_num:系列商品总评论数
  • praise_degree:系列商品总好评度
  • tag_list:系列商品总评价标签
  • single_comment_num:当前商品评论条数
  • single_tags:当前商品评价标签
  • member:顾客会员级别
  • star:评星等级
  • comment:评语
  • pic_num:评论图片数/视频数
  • order:订单详情(包含订单形式、下单日期等)

1.获取商品信息入口--商品列表链接获取

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第1张图片        爬取商品信息首先得有商品信息入口,这里直接从京东的分类中进入商品列表页面,没有对搜索关键词进行处理,仅处理了商品的页码。

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第2张图片

       翻看网页,发现共有16页,想用点击下一页(click()的方式)实现翻页,获取每一个商品列表链接。

       这里有个坑需要注意:class='pn-next disabled',在第16页依旧可以找到,如果以此设置click() 在第16页后依旧会执行,抓取到别的类目的链接。

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第3张图片

踩坑后用设置url的方式获取商品列表链接

翻看多页发现url里的页码关键字:

page:页码(奇数递增)

s:sku数(page*60+1)

构建请求url:

url='https://search.jd.com/Search?keyword=%E6%AF%8F%E5%91%A8%E4%B8%80%E8%8A%B1&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E6%AF%8F%E5%91%A8%E4%B8%80%E8%8A%B1&page='+str(i*2+1)+'&s='+str(i*60+1)+'&click=0'

网页对搜索关键词进行了加密,将 ‘ 每周一花 ’ 转化为 ' %E6%AF%8F%E5%91%A8%E4%B8%80%E8%8A%B1 '

可以用 request.unquote()对其解密

一共16页,用for循环获取所有商品列表链接:用urltrue_list接收数据

#获得 京东每周一花的16个商品列表链接 这里可以定义函数,传入要抓取的关键字或页数,使其更加灵活
urltrue_list=[]
for i in range(16):
    url='https://search.jd.com/Search?keyword=%E6%AF%8F%E5%91%A8%E4%B8%80%E8%8A%B1&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E6%AF%8F%E5%91%A8%E4%B8%80%E8%8A%B1&page='+str(i*2+1)+'&s='+str(i*60+1)+'&click=0'
    urltrue=request.unquote(url)
    urltrue_list.append(urltrue)

2.获取商品信息入口--商品详情链接获取

打开商品列表链接,每一页都有60个商品,如果直接抓取会发现只能抓到30个,原因是:后30条信息是动态加载的

我的解决办法是设置拖拽,使其将页面加载完整

#定义函数缓慢拖拽页面,使其加载完成
def buffer():
    for i in range(50):
        time.sleep(0.3)
        browser.execute_script('window.scrollBy(0,300)', '')

这样就可以获取到一页里的60个商品详情链接了,同样用for循环获取所有的商品详情链接:

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第4张图片

detail_urls = []
def get():
    for each in urltrue_list:
        browser.get(each)  # 遍历每个列表链接
        time.sleep(5)

        global detail_urls

        buffer() # 缓冲,使页面加载完整

        info = browser.find_elements_by_class_name('gl-i-wrap')# 寻找商品链接的父阶

        for line in info:
            # 获取商品列表页所有的商品链接
            detail_url = line.find_element_by_class_name('p-img').find_element_by_tag_name('a').get_attribute('href')
            detail_urls.append(detail_url)
        time.sleep(3)
        print(len(detail_urls)) # 查看长度确认是否抓取了60个连接

    return detail_urls  # 返回商品列表页所有的商品链接组成的列表
get()

3.商品详情获取

有了商品详情链接就有了真正的数据采集入口。

要采集下面截图橘黄框中的信息。

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第5张图片

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第6张图片

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第7张图片

  •  一开始是用request抓取信息的,但是抓取时发现一些例如价格,评论条数等动态的数据抓取不到,所以改用selenium抓取
for each detail_urls: # 获取商品详情链接
    browser.maximize_window()# 最大化窗口
    browser.get(each)
    time.sleep(3)

    buffer()

    #获取商品名称
    title = browser.find_element_by_class_name('sku-name').text
    #获取价格(当前商品价格)
    price = browser.find_element_by_class_name('p-price').find_elements_by_xpath('span')[1].text
    #获取系列商品总评论条数(有不同规格)
    comment_num = browser.find_element_by_id('comment-count').find_element_by_tag_name('a').text
    #获取品牌
    brand = browser.find_element_by_id('parameter-brand').find_element_by_tag_name('a').text
    #获取店名
    shop_name = browser.find_element_by_class_name('p-parameter').find_elements_by_tag_name('li')[3].get_attribute(
        'title')
    #获取商品重量
    weight = browser.find_element_by_class_name('p-parameter').find_elements_by_tag_name('li')[4].get_attribute('title')
    #获取适用人群
    user = browser.find_element_by_class_name('p-parameter').find_elements_by_tag_name('li')[5].get_attribute('title')
    #获取分类
    classify = browser.find_element_by_class_name('p-parameter').find_elements_by_tag_name('li')[6].get_attribute('title')

    buffer()

    #获取系列商品总好评度(有不同规格)
    praise_degree=browser.find_element_by_class_name('percent-con').text
    #获取系列商品总评价标签(有不同规格)
    tag_list = []
    tags = browser.find_elements_by_class_name(' tag-1')
    for tag in tags:
        tag_list.append(tag.text)

    browser.find_element_by_id('comm-curr-sku').send_keys(Keys.SPACE)  # 只看当前商品评价

    # 当前商品评论条数(单个)
    single_comment_num = browser.find_element_by_class_name('filter-list').find_elements_by_tag_name('em')[0].text
    # 当前商品评价标签
    single_tags = browser.find_element_by_class_name('filter-list').find_elements_by_tag_name('li')[1:7]
    single_tag_list = []
    for each in single_tags:
        det = each.find_element_by_tag_name('a').text
        single_tag_list.append(det)

4.商品评论获取

这个部分主要用来抓取评论详情,查看了多个商品详情,发现不管评论有多少条,最多只显示50页的数据。

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第8张图片

#抓取一页的评论详情
comment_details = []
def com_info():

    divs = browser.find_element_by_id('comment-0').find_elements_by_class_name('comment-item')
    for each in divs:
        if each.find_element_by_class_name('user-level').find_elements_by_tag_name('a'):
            member='PLUS会员'
        else:
            member='普通会员'
        #评星
        star=each.find_element_by_class_name('comment-column').\
            find_element_by_tag_name('div').get_attribute('class')
        # 评语
        comment=each.find_element_by_class_name('comment-column').find_element_by_tag_name('p').text
        # 图片数或视频数
        pic_num=len(each.find_element_by_class_name('comment-column').find_elements_by_tag_name('div')[1].\
            find_elements_by_tag_name('a'))+len(each.find_element_by_class_name('comment-column').find_elements_by_tag_name('div')[1].\
            find_elements_by_tag_name('video'))
        #订单详情
        spans = each.find_element_by_class_name('order-info').find_elements_by_tag_name('span')
        order=[]
        for index, everyone in enumerate(spans):
            order.append(spans[index].text)

        single=[member,star,comment,pic_num,order]
        comment_details.append(single)

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第9张图片

多页的数据依旧用for循环获取

for i in range(50): #这里的50设置的有问题,有些商品评价没有这么多,需要写if判断来决定循环多少次
    com_info()
    browser.find_elements_by_class_name('ui-pager-next')[0].send_keys(Keys.ENTER) # 点击下一页
    time.sleep(3)

四、代码实现

运行时有时候会报错:

Message: stale element reference: element is not attached to the page document

Message: no such element: Unable to locate element: {"method":"id","selector":"comm-curr-sku"}

(也可能是其他method和selector)

原因:都是因为数据没有加载完成导致,可以用增加sleep时间或者切换更流畅的网络解决

from selenium import webdriver
import time
from urllib import request
from selenium.webdriver.common.keys import Keys

#定义函数缓慢拖拽页面,使其加载完成
def buffer():
    for i in range(50):
        time.sleep(0.3)
        browser.execute_script('window.scrollBy(0,300)', '')

#定义函数,抓取商品一页的评论详情
comment_details = []
def com_info():
    #获取评论详情的父阶
    divs = browser.find_element_by_id('comment-0').find_elements_by_class_name('comment-item')

    #获取评论人群的会员分类
    for each in divs:
        if each.find_element_by_class_name('user-level').find_elements_by_tag_name('a'):
            member='PLUS会员'
        else:
            member='普通会员'
        # 评星
        star=each.find_element_by_class_name('comment-column').\
            find_element_by_tag_name('div').get_attribute('class')
        # 评语
        comment=each.find_element_by_class_name('comment-column').find_element_by_tag_name('p').text
        # 图片数或视频数
        pic_num=len(each.find_element_by_class_name('comment-column').find_elements_by_tag_name('div')[1].\
            find_elements_by_tag_name('a'))+len(each.find_element_by_class_name('comment-column').find_elements_by_tag_name('div')[1].\
            find_elements_by_tag_name('video'))

        #订单详情
        spans = each.find_element_by_class_name('order-info').find_elements_by_tag_name('span')
        order=[]
        for index, everyone in enumerate(spans):
            order.append(spans[index].text)

        single=[member,star,comment,pic_num,order]
        comment_details.append(single)


#获得 京东每周一花的16个商品列表链接 这里可以定义函数,传入要抓取的关键字或页数,使其更加灵活
urltrue_list=[]
for i in range(16):
    url='https://search.jd.com/Search?keyword=%E6%AF%8F%E5%91%A8%E4%B8%80%E8%8A%B1&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E6%AF%8F%E5%91%A8%E4%B8%80%E8%8A%B1&page='+str(i*2+1)+'&s='+str(i*60+1)+'&click=0'
    urltrue=request.unquote(url)
    urltrue_list.append(urltrue)

# 定义函数,获取商品列表页所有的商品详情链接
browser = webdriver.Chrome()
detail_urls = []
def get():
    for each in urltrue_list:
        browser.get(each)  # 遍历每个链接
        time.sleep(5)

        global detail_urls

        buffer() # 缓冲,使页面加载完整

        info = browser.find_elements_by_class_name('gl-i-wrap')# 寻找商品链接的父阶

        for line in info:
            # 获取商品列表页所有的商品链接
            detail_url = line.find_element_by_class_name('p-img').find_element_by_tag_name('a').get_attribute('href')
            detail_urls.append(detail_url)
        time.sleep(3)
        print(len(detail_urls)) # 查看长度确认是否抓取了60个连接

    return detail_urls  # 返回商品列表页所有的商品链接组成的列表
get()

import os
os.mkdir('txt')
os.chdir('txt')


#遍历商品详情页,抓取目标数据,  这里可以对获取的每一个数据分开定义函数
result=[]
for index,each in enumerate(detail_urls): # 获取商品详情链接
    #browser.maximize_window()# 最大化窗口
    browser.get(each)
    time.sleep(3)

    file = open(str(index)+'.txt', 'w', encoding='utf-8')

    buffer()

    #获取商品名称
    title = browser.find_element_by_class_name('sku-name').text
    #获取价格(当前商品价格)
    price = browser.find_element_by_class_name('p-price').find_elements_by_xpath('span')[1].text
    #获取系列商品总评论条数(有不同规格)
    comment_num = browser.find_element_by_id('comment-count').find_element_by_tag_name('a').text
    #获取品牌
    brand = browser.find_element_by_id('parameter-brand').find_element_by_tag_name('a').text
    #获取店名
    shop_name = browser.find_element_by_class_name('p-parameter').find_elements_by_tag_name('li')[3].get_attribute(
        'title')
    #获取商品重量
    weight = browser.find_element_by_class_name('p-parameter').find_elements_by_tag_name('li')[4].get_attribute('title')
    #获取适用人群
    user = browser.find_element_by_class_name('p-parameter').find_elements_by_tag_name('li')[5].get_attribute('title')
    #获取分类
    classify = browser.find_element_by_class_name('p-parameter').find_elements_by_tag_name('li')[6].get_attribute('title')

    buffer()

    #获取系列商品总好评度(有不同规格)
    praise_degree=browser.find_element_by_class_name('percent-con').text
    #获取系列商品总评价标签(有不同规格)
    tag_list = []
    tags = browser.find_elements_by_class_name(' tag-1')
    for tag in tags:
        tag_list.append(tag.text)

    browser.find_element_by_id('comm-curr-sku').send_keys(Keys.SPACE)  # 只看当前商品评价

    # 当前商品评论条数(单个)
    single_comment_num = browser.find_element_by_class_name('filter-list').find_elements_by_tag_name('em')[0].text
    # 当前商品评价标签
    single_tags = browser.find_element_by_class_name('filter-list').find_elements_by_tag_name('li')[1:7]
    single_tag_list = []
    for each in single_tags:
        det = each.find_element_by_tag_name('a').text
        single_tag_list.append(det)

    detail=[title,price,brand,shop_name,weight,user,classify,comment_num,praise_degree,tag_list,single_comment_num,single_tag_list]
    result+=detail # 将以上信息放到result列表中

    # 评论详情 包含用户会员等级、评星、评语、图片/视频数及订单详情
    for i in range(50): #这里的50设置的有问题,有些商品评价没有这么多,需要写if判断来决定循环多少次
        com_info()
        browser.find_elements_by_class_name('ui-pager-next')[0].send_keys(Keys.ENTER) #点击评论的下一页
        time.sleep(3)


    print(comment_details)
    con_text=comment_details

    # 存储   这里应该将存储单独定义函数
    # 将所有的商品信息存入到一个excel中,便于做行业分析
    # 将每个产品的评语分别存入txt文件便于做商品分析和用户分析

    file.write(str(comment_details)) #将每个商品的评语详情写入单独的txt文件

from openpyxl import Workbook

workbook=Workbook()
sheet=workbook.active
sheet.title='每周一花商品数据'
sheet.append('商品名称,价格,品牌,店名,商品重量,适用人群,商品分类,系列商品总评论数,系列商品总好评度,系列商品总评价标签'
             '当前商品评论条数,当前商品评价标签'.split(','))
#花材与产地因为信息不完整,没有抓取     如有分析需求再行补抓
for each in result:
    sheet.append(each)

workbook.save('每周一花商品数据.xlsx')

五、运行结果

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第10张图片

[Python] python + selenium 抓取 京东商品数据(商品名称,售价,店铺,分类,订单信息,好评率,评论等)_第11张图片

六、结语

 python是万能的,我不是……

这篇博文仅记录自己编程的过程,为这段代码做个总结和review,有很多拙劣的地方,有时间再做优化。

你可能感兴趣的:(数据挖掘,编程语言,爬虫,Python)