今天闲暇之余写了一个爬虫例子。经过爬虫去爬取京东的用户评价,经过分析爬取的数据能获得不少结果,好比,哪种颜色的胸罩最受女性欢迎,以及中国女性的平均size(仅供参考哦~)html
打开开发者工具-network,在用户评价页面咱们发现浏览器有这样一个请求python
经过分析咱们发现主要用的参数有三个productId,page,pageSize。后两个为分页参数,productId是每一个商品的id,经过这个id去获取商品的评价记录,因此咱们只须要知道每一个商品的productId就垂手可得的获取评价了。再来分析搜索页面的网页源代码mongodb
经过分析咱们发现每一个商品都在li标签中,而li标签又有一个data-pid属性,这个对应的值就是商品的productId了。数据库
大概了解了整个流程,就能够开始咱们的爬虫工做了。json
首先咱们须要在搜索页面获取商品的id,为下面爬取用户评价提供productId。key_word为搜索的关键字,这里就是【胸罩】浏览器
import requests
import re
""" 查询商品id """
def find_product_id(key_word):
jd_url = 'https://search.jd.com/Search'
product_ids = []
# 爬前3页的商品
for i in range(1,4):
param = {'keyword': key_word, 'enc': 'utf-8', 'page': i}
response = requests.get(jd_url, params=param)
# 商品id
ids = re.findall('data-pid="(.*?)"', response.text, re.S)
product_ids += ids
return product_ids
复制代码
将前三页的商品id放入列表中,接下来咱们就能够爬取评价了app
咱们经过分析preview发现获取用户评价这个请求响应的格式是一个字符串后面拼接了一个json(以下图),因此咱们只要将无用的字符删除掉,就能够获取到咱们想要的json对象了。ide
而在json对象中的comments的内容就是咱们最终想要的评价记录工具
""" 获取评论内容 """
def get_comment_message(product_id):
urls = ['https://sclub.jd.com/comment/productPageComments.action?' \
'callback=fetchJSON_comment98vv53282&' \
'productId={}' \
'&score=0&sortType=5&' \
'page={}' \
'&pageSize=10&isShadowSku=0&rid=0&fold=1'.format(product_id, page) for page in range(1, 11)]
for url in urls:
response = requests.get(url)
html = response.text
# 删除无用字符
html = html.replace('fetchJSON_comment98vv53282(', '').replace(');', '')
data = json.loads(html)
comments = data['comments']
t = threading.Thread(target=save_mongo, args=(comments,))
t.start()
复制代码
在这个方法中只获取了前10页的评价的url,放到urls这个列表中。经过循环获取不一样页面的评价记录,这时启动了一个线程用来将留言数据存到到MongoDB中。fetch
咱们继续分析评价记录这个接口发现咱们想要的两条数据
productColor:产品颜色
productSize:产品尺寸
# mongo服务
client = pymongo.MongoClient('mongodb://127.0.0.1:27017/')
# jd数据库
db = client.jd
# product表,没有自动建立
product_db = db.product
# 保存mongo
def save_mongo(comments):
for comment in comments:
product_data = {}
# 颜色
# flush_data清洗数据的方法
product_data['product_color'] = flush_data(comment['productColor'])
# size
product_data['product_size'] = flush_data(comment['productSize'])
# 评论内容
product_data['comment_content'] = comment['content']
# create_time
product_data['create_time'] = comment['creationTime']
# 插入mongo
product_db.insert(product_data)
复制代码
由于每种商品的颜色、尺寸描述上有差别,为了方面统计,咱们进行了简单的数据清洗。这段代码很是的不Pythonic。不过只是一个小demo,你们无视便可。
def flush_data(data):
if '肤' in data:
return '肤色'
if '黑' in data:
return '黑色'
if '紫' in data:
return '紫色'
if '粉' in data:
return '粉色'
if '蓝' in data:
return '蓝色'
if '白' in data:
return '白色'
if '灰' in data:
return '灰色'
if '槟' in data:
return '香槟色'
if '琥' in data:
return '琥珀色'
if '红' in data:
return '红色'
if '紫' in data:
return '紫色'
if 'A' in data:
return 'A'
if 'B' in data:
return 'B'
if 'C' in data:
return 'C'
if 'D' in data:
return 'D'
复制代码
这几个模块的功能编写完毕,下面只须要将他们联系起来
# 建立一个线程锁
lock = threading.Lock()
# 获取评论线程
def spider_jd(ids):
while ids:
# 加锁
lock.acquire()
# 取出第一个元素
id = ids[0]
# 将取出的元素从列表中删除,避免重复加载
del ids[0]
# 释放锁
lock.release()
# 获取评论内容
get_comment_message(id)
product_ids = find_product_id('胸罩')
for i in (1, 5):
# 增长一个获取评论的线程
t = threading.Thread(target=spider_jd, args=(product_ids,))
# 启动线程
t.start()
复制代码
上面代码加锁的缘由是为了防止重复消费共享变量
运行以后的查看MongoDB:
获得结果以后,为了能更直观的表现数据,咱们能够用matplotlib库进行图表化展现
import pymongo
from pylab import *
client = pymongo.MongoClient('mongodb://127.0.0.1:27017/')
# jd数据库
db = client.jd
# product表,没有自动建立
product_db = db.product
# 统计如下几个颜色
color_arr = ['肤色', '黑色', '紫色', '粉色', '蓝色', '白色', '灰色', '香槟色', '红色']
color_num_arr = []
for i in color_arr:
num = product_db.count({'product_color': i})
color_num_arr.append(num)
# 显示的颜色
color_arr = ['bisque', 'black', 'purple', 'pink', 'blue', 'white', 'gray', 'peru', 'red']
#labeldistance,文本的位置离远点有多远,1.1指1.1倍半径的位置
#autopct,圆里面的文本格式,%3.1f%%表示小数有三位,整数有一位的浮点数
#shadow,饼是否有阴影
#startangle,起始角度,0,表示从0开始逆时针转,为第一块。通常选择从90度开始比较好看
#pctdistance,百分比的text离圆心的距离
#patches, l_texts, p_texts,为了获得饼图的返回值,p_texts饼图内部文本的,l_texts饼图外label的文本
patches,l_text,p_text = plt.pie(sizes, labels=labels, colors=colors,
labeldistance=1.1, autopct='%3.1f%%', shadow=False,
startangle=90, pctdistance=0.6)
#改变文本的大小
#方法是把每个text遍历。调用set_size方法设置它的属性
for t in l_text:
t.set_size=(30)
for t in p_text:
t.set_size=(20)
# 设置x,y轴刻度一致,这样饼图才能是圆的
plt.axis('equal')
plt.title("内衣颜色比例图", fontproperties="SimHei") #
plt.legend()
plt.show()
复制代码
运行代码,咱们发现肤色的最受欢迎 其次是黑色 (钢铁直男表示不知道是否是真的...)
接下来咱们再来统计一下size 的分布图,这里用柱状图进行显示
index=["A","B","C","D"]
client = pymongo.MongoClient('mongodb://127.0.0.1:27017/')
db = client.jd
product_db = db.product
value = []
for i in index:
num = product_db.count({'product_size': i})
value.append(num)
plt.bar(left=index, height=value, color="green", width=0.5)
plt.show()
复制代码
运行后咱们发现 B size的女性更多一些
最后,欢迎你们关注个人公众号(python3xxx)。天天都会推送不同的Python干货。