🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟
📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主!
👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"挖山不止"的毅力为开发者们搬开知识道路上的重重阻碍!
💎【行业认证·权威头衔】
✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家
✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主
✔ 技术生态共建先锋:横跨鸿蒙、云计算、AI等前沿领域的技术布道者
🏆【荣誉殿堂】
🎖 连续三年蝉联"华为云十佳博主"(2022-2024)
🎖 双冠加冕CSDN"年度博客之星TOP2"(2022&2023)
🎖 十余个技术社区年度杰出贡献奖得主
📚【知识宝库】
覆盖全栈技术矩阵:
◾ 编程语言:.NET/Java/Python/Go/Node…
◾ 移动生态:HarmonyOS/iOS/Android/小程序
◾ 前沿领域:物联网/网络安全/大数据/AI/元宇宙
◾ 游戏开发:Unity3D引擎深度解析
每日更新硬核教程+实战案例,助你打通技术任督二脉!
💌【特别邀请】
正在构建技术人脉圈的你:
👍 如果这篇推文让你收获满满,点击"在看"传递技术火炬
💬 在评论区留下你最想学习的技术方向
⭐ 点击"收藏"建立你的私人知识库
🔔 关注公众号获取独家技术内参
✨与其仰望大神,不如成为大神!关注"愚公搬代码",让坚持的力量带你穿越技术迷雾,见证从量变到质变的奇迹!✨ |
文章目录
🚀前言
经过前面几篇的系统准备,我们已经完成了电商数据侦探项目的需求分析、系统架构规划、UI界面设计以及数据库表结构设计。现在,终于到了本项目最“核心”也最令人期待的一步——开始爬取真实的电商数据!
在电商数据爬取实战中,我们不仅要面对复杂多变的页面结构,还需要巧妙应对各种反爬机制,比如验证码、动态加载、IP封锁等。如何精准高效地获取我们所需的商品信息、价格走势、用户评价等,是每一个爬虫开发者必须解决的问题。
在本篇文章中,我们将带你一步步完成以下关键内容:
- 目标网站分析:选定合适的电商平台,深入分析其页面结构、数据加载方式,明确爬取对象和策略;
- 爬虫规则编写:使用 Scrapy 或 Requests + BeautifulSoup,编写爬虫代码,提取商品标题、价格、评分、销量等关键数据;
- 反爬机制应对:结合 UA 伪装、请求延迟、代理池等方法,提升爬虫的稳定性与隐蔽性;
- 数据入库与验证:将爬取到的电商数据存入之前设计的数据库中,并验证数据的完整性与准确性;
- 调试与优化:在实战中发现问题、调试代码、优化逻辑,让爬虫运行更加流畅、高效。
通过本篇文章的实践操作,你将实现电商数据从“看得到”到“抓得下”的转变,也将切实掌握应对真实网络环境中各种挑战的能力。这不仅是一次技术的历练,更是对你从“入门”走向“精通”的重要一跳。
🚀一、爬取数据
🔎1.获取京东商品热卖排行信息
在获取京东商品热卖排行信息时,首先需要定位要爬取的商品类别,并确定需要爬取的关键信息(如商品的图片、商品的名称等)。接下来,找到商品热卖排行的网络地址,并发送请求获取这些信息。获取京东商品热卖排行信息的业务流程如下图所示。
获取京东商品热卖排行信息的具体步骤:
-
打开京东排行榜首页
访问网址 https://top.jd.com/,依次选择“全部分类” → “电脑、办公” → “外设产品”,如图所示。
-
选择“查看完整榜单”
在外设产品热卖排行榜页面,点击“查看完整榜单”,如图所示。
-
使用开发者工具获取请求信息
在打开的“外设产品热卖榜”页面中,按F12键打开“开发者工具”。选择“网络监视器”并在网络类型中选择JS,再按F5刷新页面。此时,页面将显示多条网络请求信息,如图所示。
-
查找相关请求信息
在众多请求信息中,使用搜索区域查找与商品名称(例如“罗技”)相关的请求信息。单击该请求,并通过预览信息查看返回的数据是否可用,如图所示。
- 如果返回的数据与页面中的商品信息完全一致,可以确认该请求为所需的“获取京东商品热卖排行信息”的网络请求。
-
获取请求地址
在请求结果核对完成后,选择Headers选项,找到该请求的请求地址,如图所示。
- 测试发现有效地址为
https://ch.jd.com/hotsale2?cateid=686
,并且参数cateid=686
为必需,其他参数可忽略。获取请求地址时需要以京东官方网站更新的地址为准。
- 测试发现有效地址为
-
获取商品图片地址
请求结果中显示商品图片的地址,但直接访问该地址可能无法显示商品图片。此时,可以查看网页HTML代码中商品图片的网络地址,并与请求结果中的地址进行核对。-
在“商品热卖排行榜”页面的HTML代码中找到``标签内的src属性地址,如图所示。
-
比较两者后发现,图片地址的后半部分相同。拼接固定的图片前半部分地址与不同商品的地址参数,即可获取完整的商品图片地址。
-
-
拼接商品图片地址
根据以上规律,将固定的前半部分地址与商品的不同地址参数拼接,如图所示。
例如,拼接后的商品图片地址为
http://img11.360buyimg.com/n1/s320x320...
,在浏览器中直接访问该地址将显示商品图片(如图所示)。
-
创建爬虫脚本
在项目文件夹中创建名为crawl
的Python文件,该文件用于爬取网页信息。爬虫脚本首先导入爬取网页所需的模块,然后定义一个用于保存排行数据的列表。示例代码如下:import requests # 网络请求模块 from urllib.request import urlretrieve # 直接远程下载图片 import shutil # 文件夹控制 import json # 导入json模块 import re # 导入re模块 import os # os模块 rankings_list = [] # 保存排行数据的列表
-
创建Crawl类和方法
在爬虫脚本中创建Crawl
类,并在该类中定义get_rankings_json()
方法。该方法中包含3个用于保存爬取信息的列表,发送网络请求并处理返回结果。示例代码如下:class Crawl(object): # 获取排行 def get_rankings_json(self, url): self.jd_id_list = [] # 保存京东id的列表 self.name_list = [] # 保存商品名称的列表 self.good_list =[] # 保存好评率的列表 response = requests.get(url) # 发送网络请求,获取服务器响应 json_str = str(response.json()) # 将请求结果的json信息转换为字符串 dict_json = eval(json_str) # 将json字符串信息转换为字典,方便提取信息 jd_id_str ='' # 每次获取数据之前,先将保存图片的文件夹清空,清空后再创建目录 if os.path.exists('img_download'): # 判断img目录是否存在 shutil.rmtree('img_download') # 删除img目录 os.makedirs('img_download') # 创建img目录 for index,i in enumerate(dict_json['products']): id = i['wareId'] # 京东id号码 J_id = 'J_'+i['wareId'] # 京东id,添加J_用于作为获取价格参数 self.jd_id_list.append(id) # 将商品id添加至列表中 name = i['wareName'] # 商品名称 self.name_list.append(name) # 将商品名称添加至列表中 good = i['GoodRate'] # 好评率 self.good_list.append(str(good)+'%') # 将好评率添加至列表中 jd_id_str = jd_id_str + J_id+',' # 拼接京东id字符串 if index<=10: # 图片地址 imgPath = 'http://img13.360buyimg.com/n1/s320x320_'+i['imgPath'] urlretrieve(imgPath,'img_download/'+str(index)+'.jpg') # 根据下标命名图片名称 return jd_id_str
-
创建文件夹
在项目文件夹中创建3个文件夹,分别为img_download
(保存下载的图片)、img_resources
(保存图片资源)、ui
(保存窗体UI文件)。
🔎2.获取价格信息
在“获取京东商品热卖排行信息”的请求结果中没有找到价格信息,因此需要额外找到获取商品价格的请求地址,并根据返回的结果获取对应的商品价格。以下是获取价格信息的业务流程。
获取价格信息的步骤:
-
搜索价格信息
在浏览器的“开发者工具”中,搜索与价格相关的关键词,如第一个商品的价格“59.00”,然后点击旁边的“刷新”按钮,显示与关键词匹配的请求信息。点击该请求,查看其返回的数据是否可用。
-
核对请求结果
通过选择请求信息中的“Headers”选项,可以找到请求的地址。测试发现有一个有效的请求地址为:
https://p.3.cn/prices/mgets?type=1&skulds={id_str}
其中,{id_str}
是多个商品ID的组合,多个商品ID之间用逗号分隔。例如,查询3个商品价格的请求地址为:
https://p.3.cn/prices/mgets?type=1&skulds=8753276,4484537,J28748897705
返回的JSON格式的数据如下所示:[ {"op": "59.00", "m": "69.00", "id": "J8753276", "p": "59.00"}, {"p": "59.90", "m": "59.90", "id": "I4484537", "p": "22.50"}, {"op": "380.00", "m": "499.00", "id": "J28748897705", "p": "348.00"} ]
-
在Crawl类中实现获取价格的方法
在crawl.py
文件的Crawl
类中,创建get_price()
方法来获取热销商品排行榜中的价格信息。该方法首先清空排行数据列表,然后根据商品ID字符串发送请求,获取商品价格并将数据添加到列表中。以下是实现代码:def get_price(self, id): rankings_list.clear() # 清空排行数据的列表 price_url = 'http://p.3.cn/prices/mgets?type=1&skuIds={id_str}' # 获取价格的网络请求地址 response = requests.get(price_url.format(id_str=id)) # 将京东id作为参数发送获取商品价格的网络请求 price = response.json() # 获取价格json数据,该数据为list类型 for index, item in enumerate(price): # 商品名称 name = self.name_list[index] # 京东价格 jd_price = item['p'] # 每个商品的京东id jd_id = self.jd_id_list[index] # 好评率 good = self.good_list[index] # 将所有数据添加到列表中 rankings_list.append((index+1,name, jd_price, jd_id,good)) return rankings_list # 返回所有排行数据列表
🔎3.获取评价信息
商品评价信息并不在“外设产品热卖榜”的页面中,因此需要通过商品的详情页面来获取评价信息。以下是获取评价信息的步骤和方法。
获取评价信息的步骤:
-
打开商品详情页面
在“外设产品热卖榜”网页中选择任意商品,进入商品详情页面,点击“商品评价”,选择“只看当前商品评价”。然后打开浏览器的“开发者工具”并选择“网络监视器”。在网页的“推荐排序”中选择“时间排序”。
-
查找请求信息
在“推荐排序”选择“时间排序”后,网络监视器会显示触发的请求信息,查找类型为script
的请求。
-
获取评价信息的请求地址
在请求信息中找到获取评价信息的网络请求地址。分析后发现,该请求需要填写6个参数,具体参数及含义如下表所示: -
在Crawl类中实现获取评价信息的方法
在crawl.py
文件的Crawl
类中,创建get_evaluation()
方法来获取商品的评价信息。该方法定义必要的请求参数,发送请求并提取评价数据,最后根据需求返回所需的评价信息。以下是实现代码:def get_evaluation(self, score, id): # 创建头部信息 headers = {'User-Agent': 'OW64; rv:59.0) Gecko/20100101 Firefox/59.0'} # 评价请求地址参数,callback为对应书名json的id, # productId书名对应的京东id # score评价等级参数差评为1、中评为2、好评为3,0为全部 # sortType类型,6为时间排序,5为推荐排序 # pageSize每页显示评价10条 # page页数 params = { 'callback': 'fetchJSON_comment98vv10635', 'productId': id, 'score': score, 'sortType': 6, 'pageSize': 10, 'isShadowSku': 0, 'page': 0, } # 评价请求地址 url = 'https://club.jd.com/comment/skuProductPageComments.action' # 发送请求 evaluation_response = requests.get(url, params=params,headers=headers) if evaluation_response.status_code == 200: evaluation_response = evaluation_response.text try: # 去除json外层的括号与名称 t = re.search(r'({.*})', evaluation_response).group(0) except Exception as e: print('评价的json数据匹配异常!') j = json.loads(t) # 加载json数据 commentSummary = j['comments'] for comment in commentSummary: # 评价内容 c_contetn = comment['content'] # 时间 c_time = comment['creationTime'] # 京东昵称 c_name = comment['nickname'] # 好评差评 1差评 2-3 中评 4-5好评 c_score = comment['score'] # 判断没有指定的评价内容时 if len(commentSummary) == 0: # 返回无 return '无' else: # 根据不同需求返回不同数据,这里仅返回最新的评价时间 return commentSummary[0]['creationTime']
🔎4.定义数据库操作文件
根据前三节的学习内容,获取“京东商品热卖排行榜”的相关信息后,需要将这些信息保存到数据库中。下面是具体的实现步骤。
🦋4.1 创建 mysql.py
文件
在项目文件夹中,首先创建一个 mysql.py
文件,用于操作数据库。该文件将包含几个方法,用于连接数据库、插入数据、查询数据等。
🦋4.2 导入 MySQL 数据库模块
import pymysql
🦋4.3 创建 MySQL
类
# 数据库字段
'''
id 编号
name 商品名称
jd_price 京东价格
jd_id 京东商品id
good 好评率
middle_time 中评最新的时间
poor_time 差评最新的时间
'''
class MySQL(object):
# 连接数据库
def connection_sql(self):
# 连接数据库
self.db = pymysql.connect(host="localhost", user="root",
password="root", db="jd_peripheral", port=3306,charset='utf8')
return self.db
# 关闭数据库
def close_sql(self):
self.db.close()
🦋4.4 创建插入排行数据的方法
# 排行数据插入方法,该方法可以根据更换表名插入排行数据
def insert_ranking(self, cur, value, table):
# 插入数据的sql语句
sql_insert = "insert into {table} (id,name,jd_price,jd_id,good)" \
" values(%s,%s,%s,%s,%s)on duplicate" \
" key update name=values(name),jd_price=values(jd_price)," \
"jd_id=values(jd_id),good=values(good)".format(table=table)
try:
# 执行sql语句
cur.executemany(sql_insert, value)
# 提交
self.db.commit()
except Exception as e:
# 错误回滚
self.db.rollback()
# 输出错误信息
print(e)
🦋4.5 创建插入关注商品数据的方法
# 关注数据插入方法,该方法可以根据更换表名插入排行数据
def insert_attention(self, cur, value, table):
# 插入数据的sql语句
sql_insert = "insert into {table} (name,jd_price,jd_id,good,middle_time,poor_time)" \
" values(%s,%s,%s,%s,%s,%s)".format(table=table)
try:
# 执行sql语句
cur.executemany(sql_insert, value)
# 提交
self.db.commit()
except Exception as e:
# 错误回滚
self.db.rollback()
# 输出错误信息
print(e)
🦋4.6 查询前10名商品排行信息
# 查询排行数据表前10名商品名称,价格,好评率
def query_top10_info(self, cur):
query_sql = "select name,jd_price,good from jd_ranking where id<=10"
cur.execute(query_sql) # 执行sql语句
results = cur.fetchall() # 获取查询的所有记录
return results #返回所有数据
🦋4.7 根据商品 ID 查询排行数据
# 根据id查询排行数据表数据内容
def query_id_info(self, cur,id):
query_sql = "select name,jd_price,jd_id,good from jd_ranking where id={id}".format(id=id)
cur.execute(query_sql) # 执行sql语句
results = cur.fetchone() # 获取查询的记录
return results # 返回所有数据
🦋4.8 查询商品名称是否存在
# 查询关注商品的数据表中是否有相同的商品名称
def query_is_name(self, cur, name):
query_sql = "select count(*) from attention where name='{name}'".format(name=name)
cur.execute(query_sql) # 执行sql语句
results = cur.fetchall() # 获取查询的所有记录
return results[0][0] # 返回所有数据
🦋4.9 查询商品排行信息
# 查询排行的商品信息
def query_rankings(self, cur, table):
query_sql = "select id,name,jd_price,jd_id,good from {table}".format(table=table)
cur.execute(query_sql) # 执行sql语句
results = cur.fetchall() # 获取查询的所有记录
row = len(results) # 获取信息条数,作为表格的行
column = len(results[0]) # 获取字段数量,作为表格的列
return row, column, results # 返回信息行与信息列(字段对应的信息)
🦋4.10 查询所有商品名称
# 查询排行榜中所有的商品名称
def query_rankings_name(self, cur, table):
name_all_list =[] # 保存所有商品名称的列表
query_sql = "select name from {table}".format(table=table)
cur.execute(query_sql) # 执行sql语句
results = cur.fetchall() # 获取查询的所有记录
for r in results:
name_all_list.append(r[0].replace(' ',''))
return name_all_list # 返回所有排行商品名称的列表
🦋4.11 查询已关注商品的信息
# 查询已经关注的商品信息
def query_evaluate_info(self, cur, table):
query_sql = "select id,name,jd_price,jd_id,good,middle_time,poor_time from {table}".format(table=table)
cur.execute(query_sql) # 执行sql语句
results = cur.fetchall() # 获取查询的所有记录
if len(results)!=0:
row = len(results) # 获取信息条数,作为表格的行
column = len(results[0]) # 获取字段数量,作为表格的列
return row, column, results # 返回信息行与信息列(字段对应的信息)
else:
return 0,0,0
🦋4.12 更新关注商品信息
# 更新关注商品信息
def update_attention(self, cur, table, column, id):
sql_update = "update {table} set {column} where id = {id}".format(table=table, column=column, id=id)
try:
cur.execute(sql_update) # 执行sql语句
# 提交
self.db.commit()
except Exception as e:
# 错误回滚
self.db.rollback()
# 输出错误信息
print(e)
🦋4.13 删除关注商品信息
# 删除关注商品的信息
def delete_attention(self,cur,name):
delete_sql = "delete from attention where name='{name}'".format(name=name)
try:
cur.execute(delete_sql) # 执行sql语句
# 提交
self.db.commit()
except Exception as e:
# 错误回滚
self.db.rollback()
# 输出错误信息
print(e)