BD第3课:抓取京东商城胸罩销售数据

本文会继续抓取京东商城的商品评论数据是通过 productPageComments.action 页面获取的 JSON 数据,在这个 Url 中有一个 page 参数可以设置当前获取的评论页数,如图1所示。

BD第3课:抓取京东商城胸罩销售数据_第1张图片
enter image description here

图1 获取当前评论页数

不过将这个 Url 在浏览器中访问后,会显示如图2所示的内容,很明显,这并不是纯粹的 JSON 数据,前面还有fetchJSON_comment98vv3297,以及其他一些不属于 JSON 数据的内容,我们不需要管这些是什么东西,直接去掉就可以了。这个fetchJSON_comment98vv3297就是 Url 最后的 callback 参数的值,应该是一个回调函数,我们不需要管它,直接去掉就可以了。

BD第3课:抓取京东商城胸罩销售数据_第2张图片
enter image description here

图2 在浏览器中访问 Url

去掉这些零碎的方法很多,本例采用了直接替换的方式。代码如下:

# productId 是商品 ID,page 是页码
def getComments(productId,page):
# 定义获取评论数据的url
    url = 'https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv14&productId=' + str(productId) + '&score=0&sortType=5&page=' + str(page) + '&pageSize=10&isShadowSku=0&fold=1'
    # 向服务端发送HTTP GET请求
    r = http.request('GET',url)
    # 下面的代码开始替换json文本中的内容,以便可以解析
    c = r.data.decode('ISO-8859-1')
    c = c.replace('fetchJSON_comment98vv14(','')
    c = c.replace(')','')
    c = c.replace('false','"false"')
    c = c.replace('true','"true"')
    c = c.replace('null','"null"')
    c = c.replace(';','')
    # 将json文本转换为字典对象
    jdDict = json.loads(c)
    return jdDict

由于京东商城服务端会检测浏览器类型,所以在向服务端发送 HTTP 请求是需要加上 HTTP 请求头,为了方便,这里将 HTTP 请求头的信息都放到了 headers.txt 文件中,并编写了 str2Headers() 函数,将 headers.txt 文件中的 HTTP 请求头转换为字典对象。

def str2Headers(file):
    headerDict = {}
    f = open(file,'r')
    headersText = f.read()
    headers = re.split('\n',headersText)
    # 将每一行http请求拆分成key和value
    for header in headers:
        result = re.split(':',header,maxsplit = 1)
        headerDict[result[0]] = result[1]
    f.close()
    return headerDict
# 将headers.txt文件中的http请求头转换为字典对象(headers)
headers = str2Headers('headers.txt')

接下来的任务就是抓取搜索页面的所有商品列表,搜索页面是 Search,后面会跟一堆参数,不需要管它,只需要从返回的 HTML 代码中使用 BeautifulSoup 进行分析,得到我们想要的结果即可,实现代码如下:

# 以列表形式返回商品ID
def getProductIdList():
    # 定义用于搜索商品的Url
    url = "https://search.jd.com/Search?keyword=%E8%83%B8%E7%BD%A9&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E8%83%B8%E7%BD%A9&psort=3&click=0"
    # 向服务的发送HTTP GET请求
    r = http.request('GET', url,headers = headers)
    r = r.data.decode('ISO-8859-1')
    # 创建用于解析HTML的BeautifulSoup对象
    soup = BeautifulSoup(r,'lxml')
    links = []
    idList = []
    # 获取满足一定条件的a标签的href属性值
    tags = soup.find_all(href=re.compile('//item.jd.com/'))
    for tag in tags:
        links.append(tag['href'])
    linkList = list(set(links))
    for k in linkList:
        a = k.split('com/')
        idList.append(a[1].replace('.html','').replace('#comment',''))
    return idList   

最后就很容易了,只需要利用前面给出的两个函数抓取评论数据,然后利用 SQLite 3 模块中的 API 将抓取的数据写入 SQLite 数据库即可,下面看一下完整的实现代码。

from urllib3 import *
import sqlite3
import json
import re
import os
from bs4 import BeautifulSoup
disable_warnings()
http = PoolManager()
# 定义SQLite数据库文件名
dbPath = 'bra.sqlite'
# 链接SQLite数据库
conn = sqlite3.connect(dbPath)
cursor = conn.cursor()
# 根据产品ID和指定页数获取产品的评论数据
def getComments(productId,page):
    # 定义用于获取评论数据的Url
    url = 'https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv14&productId=' + str(productId) + '&score=0&sortType=5&page=' + str(page) + '&pageSize=10&isShadowSku=0&fold=1'
    # 向服务端发送HTTP GET请求
    r = http.request('GET',url)
    # 用ISO-8859-1编码格式对数据进行解码
    c = r.data.decode('ISO-8859-1')
    # 下面的代码开始替换json文本中的部分字符串,
    # 以便让json可以转化为字典对象
    c = c.replace('fetchJSON_comment98vv14(','')
    c = c.replace(')','')
    c = c.replace('false','"false"')
    c = c.replace('true','"true"')
    c = c.replace('null','"null"')
    c = c.replace(';','')
    jdDict = json.loads(c)
    return jdDict
# 得到指定商品ID的最大评论页数
def getMaxPage(productId):
    return getComments(productId,0)['maxPage']
# 从指定文件读取HTTP响应头,并将其转化为字典对象
def str2Headers(file):
    headerDict = {}
    f = open(file,'r')
    headersText = f.read()
    headers = re.split('\n',headersText)
    for header in headers:
        result = re.split(':',header,maxsplit = 1)
        headerDict[result[0]] = result[1]
    f.close()
    return headerDict
headers = str2Headers('headers.txt')
def getProductIdList():
    # 定义用户获取京东搜索商品搜索列表的Url
    url = "https://search.jd.com/Search?keyword=%E8%83%B8%E7%BD%A9&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E8%83%B8%E7%BD%A9&psort=3&click=0"   
    # 向服务端发送HTTP GET请求
    r = http.request('GET', url,headers = headers)
    # 用ISO-8859-1编码格式解码返回结果
    r = r.data.decode('ISO-8859-1')
    # 创建用于解析HTML代码的BeautifulSoup对象
    soup = BeautifulSoup(r,'lxml')
    links = []
    idList = []
    # 获取所有满足条件的a标签
    tags = soup.find_all(href=re.compile('//item.jd.com/'))
    for tag in tags:
        links.append(tag['href'])
    linkList = list(set(links))
    # 获取所有商品的ID
    for k in linkList:
        a = k.split('com/')
        idList.append(a[1].replace('.html','').replace('#comment',''))
    return idList
productIdList = getProductIdList()
initial = 0
# 开始抓取所有的胸罩评论数据
while initial < len(productIdList):
    try:
        # 获取商品ID
        productId = productIdList[initial]
        # 获取当前商品最大评论数
        maxnum = getMaxPage(productId)
        num = 1
        # 开始抓取特定商品的所有评论数据
        while num <= maxnum:
            try:
                jdDict = getComments(productId, num)
                comments = jdDict['comments']
                n = 0
                # 获取每一页评论的数据
                while n < len(comments):
                    comment = comments[n]
                    content = comment['content'].encode(encoding='ISO-8859-1').decode('GB18030')
                    productColor = comment['productColor'].encode(encoding='ISO-8859-1').decode('GB18030')
                    creationTime = comment['creationTime'].encode(encoding='ISO-8859-1').decode('GB18030')
                    productSize = comment['productSize'].encode(encoding = 'ISO-8859-1').decode('GB18030')
                    # 开始将评论数据写入SQLite数据库
                    cursor.execute('''insert into t_sales(color,size,source,discuss,time) 
                                    values('%s','%s','%s','%s','%s')''' 
                                    % (productColor,productSize,'京东','a',creationTime))

                    conn.commit()
                    n += 1
                num += 1        
            except Exception as e:
                print(e)                
                continue
        initial += 1
    except Exception as e:
        print(e)
conn.close()

现在可以运行这个 Python 脚本文件,首先会自动建立名为 bra.sqlite 的 SQLite 数据库,然后会将抓取的数据保存到 bra.sqlite 数据库中的t_sales表中,效果如图3所示。

BD第3课:抓取京东商城胸罩销售数据_第3张图片
enter image description here

你可能感兴趣的:(BD第3课:抓取京东商城胸罩销售数据)