Python爬虫 - 爬取京东商城某页面

前言

在CSDN问答中遇到这样一个需求:使用Selenium爬取京东商城某个页面中的商品价格信息,页面URL为:京东商城

页面分析

首先来到商城页面,打开F12,可以很清楚的找到目标
在这里插入图片描述
在控制台用xpath选中,正好是20个商品,没有任何问题,那么直接上代码
在这里插入图片描述

Selenium尝试

import time
from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://mall.jd.com/view_search-1056224-9061630-99-1-20-1.html')
elements = driver.find_elements_by_xpath('//span[@class="jdNum"]')
for e in elements:
    print(e.text)
driver.close()

运行一下,问题来了,竟然只有前部分商品的价格被爬取到,其余的为一个空。

再次回到页面进行逐一检查,果然,部分商品没有价格的文字和 preprice 属性:
在这里插入图片描述
多次刷新检查页面后发现:当鼠标滚轮滑动到该商品时,它才会显示出价格。那么我们给selenium也加一个鼠标滑轮滚动命令,并休眠2秒:

driver.execute_script("var action=document.documentElement.scrollTop=50000")
time.sleep(2)

结果正常,可以获取到页面所有的商品价格。本来问题到这就该结束了,但是提问题的小伙伴反应并不能解决问题,那么换一种爬取方式:requests请求接口。

分析接口

价格是如何出现的

首先可以确定的是,价格是在滑动滚轮后出现的,那么检查这个过程:
首先打开商城页面,F12,刷新一下页面,打开Network选项,可以看到很多请求,这里我们把它全部清掉:
在这里插入图片描述
然后准备监听新的请求,滑动鼠标滚轮使页面往下,果然有新的请求出现,大部分是一些图片,忽略掉图片请求,重点关注其他的。一个一个的点开这些请求,并打开Response Preview,最终找到了价格数据:
在这里插入图片描述

Postman分析请求

把上述的请求复制到Postman中,点击发送却是一个空,这是为什么呢。
一般来说这种情况可能是某请求参数不正确或者某请求头不正确。那么进行请求参数检查,逐一取消某些请求参数,也就是在Postman中取消勾选,看看哪些参数是必须的,哪些是非必须的:
在这里插入图片描述
这里我比较幸运,第一次取消传递callback参数就得到了正确的json响应。接着,我们再关注一下参数skuids,有电商经验的肯定知道sku,而这里的ids也很明确的告诉我们参数是由多个id组成的。

关注传递的skuids,它的数据是一个字符串:J_59269612194%2CJ_69200853812%2CJ_58574108156%2CJ_69283554933%2C
%2C很显眼,因为URL链接中百分号代表了转译,百度一下就知道%2C是逗号 - ‘,’.因此,这个字符串就是由多个skuid用逗号连接起来的。

寻找SKUID

好了,现在我们只需要找到多个商品的SKUID,并把它们用逗号连接起来,请求上述的接口就能获得对应的价格了。

复制一个SKUID:J_5926961219,首先尝试Ctrl + F在页面源码中查找,并没有结果。然后打开F12,在Elements中Ctrl + F进行查找,也没有结果。最后,我们再定位到某个产品的li标签下:
在这里插入图片描述
这个data-sku是啥就不用多说了吧,前面加上J_就是参数skuid了。其实这里也可以直接Ctrl + F查一下sku、skuid的。最后,我在价格元素中也找到了sku,编写代码时也是抓取的该元素的jdprice属性
在这里插入图片描述

获取SKUID

在页面源码中Ctrl + F 搜索这个skuid:65882949356,没有结果,甚至搜索样式:jdNum也没有结果,这说明,商品这部分的html极有可能是动态加载的

再次来到F12,Network先把请求都清掉,刷一下页面,在XHR、JS选项中查看每一个请求的Preview信息。
在这里插入图片描述
查看请求之前,我们可以根据接口名来猜测请求返回的信息:例如 getShopHeader,很容易理解为商店头部信息,应该不会是我们需要的商品信息。

最后,逐一检查Preview信息后,找到一个返回长串Html代码的请求:
在这里插入图片描述
把它copy到文本中,Ctrl + F查一下 jdNum,出现
<span class='jdNum' jshop='price' jdprice='59269612194' >
OK,发现目标。另外,这个接口中的pageSize、pageNo等一些参数就不用多说了,如果需要进一步爬取,更改这些参数即可。

其实寻找这个接口的过程也有一些小技巧:当时看到这个请求中的pageNo=1就意识到可能就是商品信息,因为商品信息就是分页展示的。甚至我们可以在Network中用pageNo、pageSize、page等关键词过滤请求,这样能直接找到这个请求。

Postman测试

再次来到Postman,测试一下刚找到的接口。点击发送没有正确的响应,检查参数以及请求头,检查过程就省略了。这次是请求头的原因:缺少了referer。爬了这么多网站,referer也是老熟人了,请求头加上它即可。

Demo代码

最后,上一个简单的Demo

import requests
from lxml import etree
import json

# 必须加 referer, 否则第一次请求无结果
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/74.0.3729.157 Safari/537.36',
    'referer': "https://mall.jd.com/"
}

info = requests.get(
    'https://module-jshop.jd.com/module/getModuleHtml.html?orderBy=99&direction=1&pageNo=1&categoryId=9061630'
    '&pageSize=20&pagePrototypeId=8&pageInstanceId=111774908&moduleInstanceId=258367169&prototypeId=55555&templateId'
    '=905542&appId=1056224&layoutInstanceId=258367169&origin=0&shopId=813953&venderId=815911&callback'
    '=jshop_module_render_callback', headers=headers).text
info = info[29:-1]

json_info = json.loads(info)

# 抓取商品SKU
tree = etree.HTML(json_info['moduleText'])
skus = tree.xpath('//span[@class="jdNum"]/@jdprice')

# 商品SKU前加上  J_
new_skus = ['J_' + sku for sku in skus]

# 使用多个商品SKU 请求价格接口
skus_string = ','.join(new_skus)
result = requests.get(f'https://f-mall.jd.com/prices/mgets?source=jshop&type=mgets&area=18_1482_48939_0&skuids={skus_string}&_=1624516262221', headers=headers).json()
print(result)

# result: 结果是一个json,包含所有请求商品的价格
# [{'p': '69.00', 'op': '69.00', 'm': '169.00', 'cbf': 0, 'id': 'J_69200853812'}, {'p': '179.00',
# 'op': '179.00', 'm': '369.00', 'cbf': 0, 'id': 'J_66266801909'}, ... 省略

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值