2025年3月6日 星期四 甲辰(龙)年 月初五 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > Python

Python爬虫:爬取京东商品评论(处理json) urllib3+bs4+sqlite3

时间:08-21来源:作者:点击数:22

通过观察京东商品页面返回的评论数据是 JSON 格式的,所以抓取指定评论需要使用 JSON 模块中相应的 API 进行分析,而从搜索页面抓取的商品列表需要分析 HTML 代码,所以使用 bs4。在对数据进行分析整理后,需要将数据保存到 sqlite 数据库中,其他模块还包括 os 和 fake_useragent(获取假的消息头,之前用一个消息头好像被封了,带秀)。

  • from urllib3 import *
  • import sqlite3
  • import json
  • import os
  • from bs4 import BeautifulSoup
  • from fake_useragent import UserAgent

首先我们来到京东随便搜索一个商品,并且进入商品具体页面,检测network

不难发现这个页面获取了评论有关的json数据:

将此url在浏览器中访问后

这并不是纯粹的 json 数据,前面还有 fetchJSON_comment...,以及其他一些不属于 JSON 数据的内容,通过不同的商品面叶可以发现 callback 参数的值基本上都不同,回调函数,不妨去掉试试

哈!果然能正常访问,而且内容中也没有了fetchJSON_啥啥啥的,这又方便了不少

于是我们得到了一个基本格式https://sclub.jd.com/comment/productPageComments.action?productId=***&score=0&sortType=5&page=***&pageSize=10&isShadowSku=0&fold=1,不过要注意的是第一页是0

当然其中还有一些零碎的地方需要转为json类型格式(需要将null,false,true用双引号括起来),可以直接通过字符串替换的方式,然后将json数据转换为字典对象

  • def getRateDetail(productId, page):
  • url = 'https://sclub.jd.com/comment/productPageComments.action?productId='+ str(productId) + '&score=0&sortType=5&page='+str(page)+'&pageSize=10&isShadowSku=0&fold=1'
  • r = http.request('GET', url, headers=head)
  • c = r.data.decode('GB18030')
  • c = c.replace('null', '"null"')
  • c = c.replace('false', '"false"')
  • c = c.replace('true', '"true"')
  • # 将json数据转换为字典对象
  • jdjson=json.loads(c)
  • return jdjson

并且在此页上有页数信息

以下为获取每个商品页最大评论页数

  • #获取具体商品的最后一页
  • def getLastPage(productId):
  • jdjson = getRateDetail(productId,1)
  • return jdjson['maxPage']

接下来的任务就是抓取搜索页面的所有商品id,商品页网址如https://item.jd.com/5734174.html,不难猜测5734174就是商品id,来到搜素页

可见每个li标签中的data-sku就是商品id,接下来自然就是通过美汤来获取所有商品id的列表

  • # 以列表形式返回商品ID
  • def getProductIdList():
  • url='https://search.jd.com/Search?keyword=cherry&enc=utf-8&wq=cherry&pvid=2db50b439b0747408233915adca72e88'
  • r = http.request('GET', url, headers=head)
  • #注意如果搜索的内容有中文,网址中就会有utf8的东西,需要ignore忽略utf8一下
  • c = r.data.decode('GB18030','ignore').encode('utf8')
  • soup = BeautifulSoup(c, 'html.parser')
  • liList=soup.find_all('li',attrs={'class':'gl-item'})
  • idList = []
  • for li in liList:
  • idList.append(li['data-sku'])
  • #去掉重复的id,不过应该不会重复(利用Set的特性)
  • idList = list(set(idList))
  • return idList

最后便是加入到sqlite数据库(注意执行完要commit一下)当中了

完整代码:

  • from urllib3 import *
  • import sqlite3
  • import json
  • import os
  • from bs4 import BeautifulSoup
  • from fake_useragent import UserAgent
  • disable_warnings()
  • http = PoolManager()
  • head = {
  • 'User-Agent': str(UserAgent().random)
  • }
  • dbPath = 'jdkb.sqlite'
  • if os.path.exists(dbPath):
  • os.remove(dbPath)
  • conn = sqlite3.connect(dbPath)
  • cursor = conn.cursor()
  • cursor.execute('''create table kb_comment
  • (id integer primary key autoincrement not null,
  • content text not null,
  • ctime text not null,
  • productName text not null);''')
  • conn.commit()
  • #获取具体商品的json数据
  • def getRateDetail(productId, page):
  • url = 'https://sclub.jd.com/comment/productPageComments.action?productId='+ str(productId) + '&score=0&sortType=5&page='+str(page)+'&pageSize=10&isShadowSku=0&fold=1'
  • r = http.request('GET', url, headers=head)
  • c = r.data.decode('GB18030')
  • c = c.replace('null', '"null"')
  • c = c.replace('false', '"false"')
  • c = c.replace('true', '"true"')
  • jdjson=json.loads(c)
  • return jdjson
  • #获取具体商品的最后一页
  • def getLastPage(productId):
  • jdjson = getRateDetail(productId,1)
  • return jdjson['maxPage']
  • # 以列表形式返回商品ID
  • def getProductIdList():
  • url='https://search.jd.com/Search?keyword=cherry&enc=utf-8&wq=cherry&pvid=2db50b439b0747408233915adca72e88'
  • r = http.request('GET', url, headers=head)
  • c = r.data.decode('GB18030','ignore').encode('utf8')
  • soup = BeautifulSoup(c, 'html.parser')
  • liList=soup.find_all('li',attrs={'class':'gl-item'})
  • idList = []
  • for li in liList:
  • idList.append(li['data-sku'])
  • #去掉重复的Utl
  • idList = list(set(idList))
  • return idList
  • init = 0
  • productIdList=getProductIdList()
  • while init < len(productIdList):
  • try:
  • productId = productIdList[init]
  • maxPage = getLastPage(productId)
  • page = 0
  • while page <= maxPage:
  • try:
  • jdjs=getRateDetail(productId,page)
  • rateList = jdjs['comments']
  • n=0
  • while n<len(rateList):
  • content = str(rateList[n]['content'])
  • time = str(rateList[n]['creationTime'])
  • productName = str(rateList[n]['referenceName'])
  • cursor.execute('''insert into kb_comment(content,ctime,productName)
  • values('%s','%s','%s')'''%(content,time,productName))
  • conn.commit()
  • n += 1
  • page += 1
  • except Exception as e:
  • continue
  • init+=1
  • except Exception as e:
  • print(e)

效果如图

···

由于sqlite一次只能 insert 500条记录,要是想爬大量数据要么分多次爬,要么就使用多线程爬虫。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门