【愚公系列】《Python网络爬虫从入门到精通》062-项目实战电商数据侦探(爬取数据)

🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟

📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主!

👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"挖山不止"的毅力为开发者们搬开知识道路上的重重阻碍!

💎【行业认证·权威头衔】
✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家
✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主
✔ 技术生态共建先锋:横跨鸿蒙、云计算、AI等前沿领域的技术布道者

🏆【荣誉殿堂】
🎖 连续三年蝉联"华为云十佳博主"(2022-2024)
🎖 双冠加冕CSDN"年度博客之星TOP2"(2022&2023)
🎖 十余个技术社区年度杰出贡献奖得主

📚【知识宝库】
覆盖全栈技术矩阵:
◾ 编程语言:.NET/Java/Python/Go/Node…
◾ 移动生态:HarmonyOS/iOS/Android/小程序
◾ 前沿领域:物联网/网络安全/大数据/AI/元宇宙
◾ 游戏开发:Unity3D引擎深度解析
每日更新硬核教程+实战案例,助你打通技术任督二脉!

💌【特别邀请】
正在构建技术人脉圈的你:
👍 如果这篇推文让你收获满满,点击"在看"传递技术火炬
💬 在评论区留下你最想学习的技术方向
⭐ 点击"收藏"建立你的私人知识库
🔔 关注公众号获取独家技术内参
✨与其仰望大神,不如成为大神!关注"愚公搬代码",让坚持的力量带你穿越技术迷雾,见证从量变到质变的奇迹!✨ |


🚀前言

经过前面几篇的系统准备,我们已经完成了电商数据侦探项目的需求分析、系统架构规划、UI界面设计以及数据库表结构设计。现在,终于到了本项目最“核心”也最令人期待的一步——开始爬取真实的电商数据

在电商数据爬取实战中,我们不仅要面对复杂多变的页面结构,还需要巧妙应对各种反爬机制,比如验证码、动态加载、IP封锁等。如何精准高效地获取我们所需的商品信息、价格走势、用户评价等,是每一个爬虫开发者必须解决的问题。

在本篇文章中,我们将带你一步步完成以下关键内容:

  1. 目标网站分析:选定合适的电商平台,深入分析其页面结构、数据加载方式,明确爬取对象和策略;
  2. 爬虫规则编写:使用 Scrapy 或 Requests + BeautifulSoup,编写爬虫代码,提取商品标题、价格、评分、销量等关键数据;
  3. 反爬机制应对:结合 UA 伪装、请求延迟、代理池等方法,提升爬虫的稳定性与隐蔽性;
  4. 数据入库与验证:将爬取到的电商数据存入之前设计的数据库中,并验证数据的完整性与准确性;
  5. 调试与优化:在实战中发现问题、调试代码、优化逻辑,让爬虫运行更加流畅、高效。

通过本篇文章的实践操作,你将实现电商数据从“看得到”到“抓得下”的转变,也将切实掌握应对真实网络环境中各种挑战的能力。这不仅是一次技术的历练,更是对你从“入门”走向“精通”的重要一跳。

🚀一、爬取数据

🔎1.获取京东商品热卖排行信息

在获取京东商品热卖排行信息时,首先需要定位要爬取的商品类别,并确定需要爬取的关键信息(如商品的图片、商品的名称等)。接下来,找到商品热卖排行的网络地址,并发送请求获取这些信息。获取京东商品热卖排行信息的业务流程如下图所示。
在这里插入图片描述

获取京东商品热卖排行信息的具体步骤:

  1. 打开京东排行榜首页
    访问网址 https://top.jd.com/,依次选择“全部分类” → “电脑、办公” → “外设产品”,如图所示。
    在这里插入图片描述

  2. 选择“查看完整榜单”
    在外设产品热卖排行榜页面,点击“查看完整榜单”,如图所示。
    在这里插入图片描述

  3. 使用开发者工具获取请求信息
    在打开的“外设产品热卖榜”页面中,按F12键打开“开发者工具”。选择“网络监视器”并在网络类型中选择JS,再按F5刷新页面。此时,页面将显示多条网络请求信息,如图所示。
    在这里插入图片描述

  4. 查找相关请求信息
    在众多请求信息中,使用搜索区域查找与商品名称(例如“罗技”)相关的请求信息。单击该请求,并通过预览信息查看返回的数据是否可用,如图所示。
    在这里插入图片描述

    • 如果返回的数据与页面中的商品信息完全一致,可以确认该请求为所需的“获取京东商品热卖排行信息”的网络请求。
  5. 获取请求地址
    在请求结果核对完成后,选择Headers选项,找到该请求的请求地址,如图所示。
    在这里插入图片描述

    • 测试发现有效地址为 https://ch.jd.com/hotsale2?cateid=686,并且参数cateid=686为必需,其他参数可忽略。获取请求地址时需要以京东官方网站更新的地址为准。
  6. 获取商品图片地址
    请求结果中显示商品图片的地址,但直接访问该地址可能无法显示商品图片。此时,可以查看网页HTML代码中商品图片的网络地址,并与请求结果中的地址进行核对。

    • 在“商品热卖排行榜”页面的HTML代码中找到``标签内的src属性地址,如图所示。
      在这里插入图片描述

    • 比较两者后发现,图片地址的后半部分相同。拼接固定的图片前半部分地址与不同商品的地址参数,即可获取完整的商品图片地址。

  7. 拼接商品图片地址
    根据以上规律,将固定的前半部分地址与商品的不同地址参数拼接,如图所示。
    在这里插入图片描述

    例如,拼接后的商品图片地址为 http://img11.360buyimg.com/n1/s320x320...,在浏览器中直接访问该地址将显示商品图片(如图所示)。
    在这里插入图片描述

  8. 创建爬虫脚本
    在项目文件夹中创建名为 crawl 的Python文件,该文件用于爬取网页信息。爬虫脚本首先导入爬取网页所需的模块,然后定义一个用于保存排行数据的列表。示例代码如下:

    import requests # 网络请求模块
    from urllib.request import urlretrieve  # 直接远程下载图片
    import shutil      # 文件夹控制
    import json        # 导入json模块
    import re          # 导入re模块
    import os          # os模块
    rankings_list = []  # 保存排行数据的列表
    
  9. 创建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
    
  10. 创建文件夹
    在项目文件夹中创建3个文件夹,分别为 img_download(保存下载的图片)、img_resources(保存图片资源)、ui(保存窗体UI文件)。

🔎2.获取价格信息

在“获取京东商品热卖排行信息”的请求结果中没有找到价格信息,因此需要额外找到获取商品价格的请求地址,并根据返回的结果获取对应的商品价格。以下是获取价格信息的业务流程。
在这里插入图片描述

获取价格信息的步骤:

  1. 搜索价格信息
    在浏览器的“开发者工具”中,搜索与价格相关的关键词,如第一个商品的价格“59.00”,然后点击旁边的“刷新”按钮,显示与关键词匹配的请求信息。点击该请求,查看其返回的数据是否可用。
    在这里插入图片描述

  2. 核对请求结果
    通过选择请求信息中的“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"}
    ]
    

    在这里插入图片描述

  3. 在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.获取评价信息

商品评价信息并不在“外设产品热卖榜”的页面中,因此需要通过商品的详情页面来获取评价信息。以下是获取评价信息的步骤和方法。
在这里插入图片描述

获取评价信息的步骤:

  1. 打开商品详情页面
    在“外设产品热卖榜”网页中选择任意商品,进入商品详情页面,点击“商品评价”,选择“只看当前商品评价”。然后打开浏览器的“开发者工具”并选择“网络监视器”。在网页的“推荐排序”中选择“时间排序”。
    在这里插入图片描述

  2. 查找请求信息
    在“推荐排序”选择“时间排序”后,网络监视器会显示触发的请求信息,查找类型为script的请求。
    在这里插入图片描述

  3. 获取评价信息的请求地址
    在请求信息中找到获取评价信息的网络请求地址。分析后发现,该请求需要填写6个参数,具体参数及含义如下表所示:

    在这里插入图片描述

  4. 在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)
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚公搬代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值