Python爬虫实战:使用Scrapy与Requests抓取京东商品数据

咖啡半糖
咖啡半糖
发布时间:2026-10-14 | 3人浏览过
原创

本文详解如何利用Python爬取京东商城商品数据。通过分析Ajax异步加载机制,结合Requests获取HTML源码,使用BeautifulSoup解析DOM结构提取data-pid及图片URL。教程涵盖简化请求URL、处理懒加载图片属性、多线程加速抓取及MySQL/MongoDB存储方案,提供完整代码逻辑与优化建议。

前言与工具介绍

前言

本文详细讲解如何利用Python技术实现京东商城数据的爬取。内容涵盖从环境搭建到代码实现的完整流程,旨在为读者提供清晰的操作指南。

主要工具

  • scrapy
  • BeautifulSoup
  • requests

京东页面分析与数据抓取策略

分析步骤

1、访问京东首页,在搜索框输入“裤子”并回车。页面跳转至搜索结果页,此即我们需要分析的起始页面。

2、观察页面可知,初始加载的内容并不完整。向下滚动时,图片会持续动态加载,这表明页面使用了Ajax技术。当滚动至底部时,页面共加载了60条商品信息。通过Chrome开发者工具检查元素,可以发现每条商品信息的结构均包裹在<li class='gl-item'></li>标签内,具体结构如下图所示:

3、查看网页源代码会发现,源码中仅包含前30条数据,后30条数据无法在源码中直接找到。这证实了数据是通过Ajax异步加载的。因此,我们需要通过抓包工具获取真实的数据接口。按下F12打开开发者工具,切换到Network(网络)标签页,筛选XHR(XMLHttpRequest)请求,即可捕获到异步加载的请求数据,抓包过程如下图所示:


4、从抓包结果中可以定位到请求的URL。该URL参数较长,我们可以尝试简化以验证其有效性。简化后的URL格式如下: https://search.jd.com/s_new.php?keyword=%E8%A3%A4%E5%AD%90&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&offset=3&wq=%E8%A3%94%E5%AD%90&page={0}&s=26&scrolling=y&pos=30&show_items={1} 其中,show_items参数对应商品的ID,page参数用于控制翻页。分析表明,只需修改这两个参数即可访问不同页面。值得注意的是,主网页的page值为奇数,而Ajax异步加载接口的page值为偶数。因此,在构造请求时,page参数应填入偶数(尽管填入奇数也能访问,但偶数符合异步加载逻辑)。show_items参数即商品ID,可在页面源码中通过查找li标签的data-pid属性获得,具体位置如下图所示:


明确了参数获取方法后,接下来即可开始编写代码。

Python代码实现详解

代码讲解

1、首先,我们需要获取网页的源代码。这里选用requests库,安装方法为pip install requests。核心代码如下:


def get_html(self):
 res = requests.get(self.url, headers=self.headers)
 html = res.text 
 return html #返回的源代码

2、根据前述分析,第二步是获取Ajax加载URL中的show_items参数,即li标签中的data-pid值。实现代码如下:


def get_pids(self):
 html = self.get_html()
 soup = BeautifulSoup(html, 'lxml') #创建BeautifulSoup对象
 lis = soup.find_all("li", class_='gl-item') #查找li标签
 for li in lis:
  data_pid = li.get("data-pid")  #得到li标签下的data-pid
  if (data_pid):
   self.pids.add(data_pid) #这里的self.pids是一个集合,用于过滤重复的

3、接下来获取前30张图片的URL,这些图片位于主网页中。需要注意的是,img标签的属性存在差异:已加载完成的图片使用src属性,而未加载的图片(懒加载)则使用data-lazy-img属性。因此,在解析页面时必须同时处理这两种情况。

具体实现代码如下:


def get_src_imgs_data(self):
 html = self.get_html()
 soup = BeautifulSoup(html, 'lxml')
 divs = soup.find_all("div", class_='p-img') # 图片
 # divs_prices = soup.find_all("div", class_='p-price') #价格
 for div in divs:
  img_1 = div.find("img").get('data-lazy-img') # 得到没有加载出来的url
  img_2 = div.find("img").get("src") # 得到已经加载出来的url
  if img_1:
   print img_1
   self.sql.save_img(img_1)
   self.img_urls.add(img_1)
  if img_2:
   print img_2
   self.sql.save_img(img_2)
   self.img_urls.add(img_2)

前30张图片已获取,现在开始处理后30张图片。这需要请求之前抓取的异步加载URL。由于前文已找到所需参数,后续处理较为直接,代码如下:


def get_extend_imgs_data(self):
 # self.search_urls=self.search_urls+','.join(self.pids)
 self.search_urls = self.search_urls.format(str(self.search_page), ','.join(self.pids)) #拼凑url,将获得的单数拼成url,其中show_items中的id是用','隔开的,因此要对集合中的每一个id分割,page就是偶数,这里直接用主网页的page加一就可以了
 print self.search_urls
 html = requests.get(self.search_urls, headers=self.headers).text #请求
 soup = BeautifulSoup(html, 'lxml') 
 div_search = soup.find_all("div", class_='p-img') #解析
 for div in div_search: 
  img_3 = div.find("img").get('data-lazy-img') #这里可以看到分开查找img属性了
  img_4 = div.find("img").get("src")
  if img_3: #如果是data-lazy-img
   print img_3
   self.sql.save_img(img_3) #存储到数据库
   self.img_urls.add(img_3)  #用集合去重
  if img_4: #如果是src属性
   print img_4
   self.sql.save_img(img_4)  
   self.img_urls.add(img_4)

4、基于上述逻辑即可完成数据爬取。考虑到效率问题,此处采用多线程策略,每个页面开启一个线程进行抓取,速度表现良好,几分钟内即可完成100个网页的数据爬取。数据存储方面,本文使用MySQL数据库,需导入MySQLdb库(具体配置请参考官方文档)。

当然,也可以选用MongoDB进行存储,但本文未涉及该部分。如需完整源码,请参考以下链接:

一、GitHub源码

二、本地下载

拓展总结与源码获取

拓展总结

观察搜索结果页URL可知,keyword和wq参数均对应用户输入的搜索词。若需爬取其他类别的商品,只需将这两个参数替换为目标关键词即可。直接输入汉字,请求库会自动进行编码处理,经测试可有效抓取源码。若需持续抓取,可将目标关键词写入文件,程序从文件中读取关键词进行循环抓取。以上仅为基础爬虫示例,未使用复杂框架。后续将介绍基于Scrapy框架的爬取方案,敬请关注本站更新。

至此,本文内容全部结束。希望本文对大家在Python学习或实际应用中有所帮助。如有任何疑问,欢迎留言交流,感谢支持。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表