首页 > 编程语言 >Python | 爬虫实战——亚马逊搜索页监控(附详细源码)

Python | 爬虫实战——亚马逊搜索页监控(附详细源码)

时间:2024-09-04 21:22:18浏览次数:6  
标签:Set Python req 爬虫 ch Header 源码 sec html

背景

做亚马逊店铺,如果你的品卖爆了,免不得遇到被人跟品、广告关键词竞争甚至是恶意投诉等事情。

如果靠人去检查产品是否正常,存在不及时的问题。

所以,基本都会想要有一个自动检测的工具。

一般是自动根据关键词,设置邮编,查看对应市场下的搜索结果页是否,然后进一步判断搜索结构页的内容是否符合预期,比如该广告词搜索结果是否存在自家产品?自己产品是否占据视频广告位?自己产品的自然排位在第几位?广告排位在第几位?有哪些竞品?……

只要能拿到这个搜索结果页,你就能自动提取和检测多个信息。

所以关键的问题是,自动获取这个搜索结果页。

方案

自动抓取亚马逊搜索结果页逻辑,本质上也比较简单,就是一个 HTTP 请求而已。

关于爬虫技术,可以参考:《认识爬虫技术》

但想要达到预期效果,面对亚马逊这个平台,有 2 个需要克服的问题:

  1. 需要设置目标市场的邮编,实现和用户实际搜索一样的市场范围。

  2. 需要克服亚马逊的反爬虫机制。

邮编设置

亚马逊的邮编信息设置,如下设置为 17888:

我没有登录,可以随意更改。

说明这个邮编信息,肯定是存在前端缓存中,那一般就在 cookie 中。

我们可以 F12 查看 cookie,但是找不到邮编对应的 cookie 信息:

但可以看到有一个 session-token 信息,大概率邮编是加密保存在其中。

这些 cookie 信息过期时间都是 1 年,所以我们可以直接把 cookie 信息放入我们的请求脚本。

查看搜索的网络请求,如下,可以看到有个 Cookie 的请求头,把上面的 cookie 信息全部包含在其中。

我们可以直接复制这个 Cookie 请求头,加入 HTTP 请求头就能实现 17888 设置邮编一样的效果。

反爬虫设置

测试下来,亚马逊的反爬虫,和大多数爬虫一样:

  1. 检查 UA 和其他请求头

  2. 检查 Cookie 信息

  3. 检查请求频率

直接在脚本 HTTP 请求头中,把上面 F12 查看到的请求头完整加入理论上就可以了,如下:

import aiohttp
import asyncio
import os
import time

def save_html(content):
    # 确保目录存在
    directory = "page"
    if not os.path.exists(directory):
        os.makedirs(directory)

    # 生成文件名
    filename = time.strftime("%Y%m%d%H%M%S") + ".html"
    filepath = os.path.join(directory, filename)

    # 保存文件
    with open(filepath, 'w', encoding='utf-8') as file:
        file.write(content)
    print("页面已保存至:", filepath)

async def monitor_amazon():
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "Accept-Encoding": "gzip, deflate, br, zstd",
        "Connection": "keep-alive",
        "Host": "www.amazon.com",
        "Pragma": "no-cache",
        "Cache-Control": "no-cache",
        "device-memory": "8",
        "sec-ch-device-memory": "8",
        "dpr": "1",
        "sec-ch-dpr": "1",
        "viewport-width": "1287",
        "sec-ch-viewport-width": "1287",
        "rtt": "250",
        "downlink": "10",
        "ect": "4g",
        "sec-ch-ua": '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"',
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": '"Windows"',
        "sec-ch-ua-platform-version": '"15.0.0"',
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-User": "?1",
        "Sec-Fetch-Dest": "document",
        "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6",
        "Cookie": "csm-sid=561-4363494-2586590; x-amz-captcha-1=1725426766590873; x-amz-captcha-2=coU0U1XjNmbWBo6t12F7Lw==; session-id=145-8557831-0273963; session-id-time=2082787201l; i18n-prefs=USD; ubid-main=135-5704831-0797008; skin=noskin; JSESSIONID=12AD7B880D398809E2385F69B353506A; session-token=JswlXQfSLBxq71q7wIMJNajjv7zTDlFSxhu+hA1idTc8X3yk1TP/yeQ8rBlKWLJXeMAX0cKAUM7NXYe/LmmGgsv9F44l0Q8EI43IanRD9e6XgYsSra04Q0RiAjvrZfAFRf6Gn222CjZ9PAAzzQ7YPq7qx5jEeaOKgtj3t0VkGVlKmTX3wWbnoIv1wJRAv3R9b3BgnIDgYX64V9hxyZQaobLX8LeI70c9uTD3bw8nOz5VMjHkdF4F8x1dzXZZp6QhmVe/ESi1qlfF2PQnt0JgHp2J+3xsDmq7rL8ogs0/haZAkS16oTC5w3ghPAuvqskUKvZRnmp6m8Xag6GSK37kmDkVr7pwyWB/; csm-hit=tb:YBQ9G3J9FVM18YJJW7QJ+s-YBQ9G3J9FVM18YJJW7QJ|1725430067985&t:1725430067985&adb:adblk_no",
    }

    # 监控的产品,搜索词
    keyword = "cat litter"
    asin = "B0CR919N3T"
    search_url = f"https://www.amazon.com/s?k={keyword.replace(' ', '+')}"

    async with aiohttp.ClientSession() as session:
        response = await session.get(search_url, headers=headers)
        html = await response.text()
        await session.close()
        save_html(html)
        if "dogs of amazon" in html.lower():
            print("搜索被标识为异常访问")
        elif asin.lower() in html.lower():
            print("在 Amazon 搜索结果页找到了关键词")
        else:
            print("在 Amazon 搜索结果页未找到 ASIN 关键词,发送警告")


# 在 Windows 中使用 SelectorEventLoop
if __name__ == '__main__':
    if os.name == 'nt':
        loop = asyncio.SelectorEventLoop()
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()

    loop.run_until_complete(monitor_amazon())
    loop.close()

代码很简单,抓取到页面后,但是,只有偶尔能成功获取到一次正常的页面,其他页面全部变 "狗",如下:

这个页面返回,明显是触发了亚马逊的返爬虫机制。

后续我尝试使用了海外的代理 IP,替换了多个和网页请求一致的请求头,但仍然一样。

相同的代码逻辑,我又改成了 Golang 脚本:

package main

import (
        "fmt"
        "io/ioutil"
        "net/http"
        "os"
        "time"
)

func saveHTML(content []byte) {
        directory := "page"
        // 确保目录存在
        if _, err := os.Stat(directory); os.IsNotExist(err) {
            os.Mkdir(directory, os.ModePerm)
        }

        // 生成文件名
        filename := time.Now().Format("20060102150405") + ".html"
        filepath := directory + "/" + filename

        // 保存文件
        err := ioutil.WriteFile(filepath, content, 0644)
        if err != nil {
                fmt.Println("保存文件失败:", err)
        } else {
                fmt.Println("页面已保存至:", filepath)
        }
}

func monitorAmazon() {
        client := &http.Client{}
        // 创建请求
        req, err := http.NewRequest("GET", "https://www.amazon.com/s?k=cat+litter", nil)
        if err != nil {
            fmt.Println("创建请求失败:", err)
            return
        }
        // 设置请求头
        req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")
        req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
        req.Header.Set("Accept-Encoding", "gzip, deflate, br, zstd")
        req.Header.Set("Connection", "keep-alive")
        req.Header.Set("Host", "www.amazon.com")
        req.Header.Set("Pragma", "no-cache")
        req.Header.Set("Cache-Control", "no-cache")
        req.Header.Set("device-memory", "8")
        req.Header.Set("sec-ch-device-memory", "8")
        req.Header.Set("dpr", "1")
        req.Header.Set("sec-ch-dpr", "1")
        req.Header.Set("viewport-width", "1287")
        req.Header.Set("sec-ch-viewport-width", "1287")
        req.Header.Set("rtt", "250")
        req.Header.Set("downlink", "10")
        req.Header.Set("ect", "4g")
        req.Header.Set("sec-ch-ua", `"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"`)
        req.Header.Set("sec-ch-ua-mobile", "?0")
        req.Header.Set("sec-ch-ua-platform", `"Windows"`)
        req.Header.Set("sec-ch-ua-platform-version", `"15.0.0"`)
        req.Header.Set("Upgrade-Insecure-Requests", "1")
        req.Header.Set("Sec-Fetch-Site", "none")
        req.Header.Set("Sec-Fetch-Mode", "navigate")
        req.Header.Set("Sec-Fetch-User", "?1")
        req.Header.Set("Sec-Fetch-Dest", "document")
        req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6")
        req.Header.Set("Cookie", "xxx cookie")  // 直接复制浏览器网络请求头中的 Cookie 值

        // 执行请求
        resp, err := client.Do(req)
        if err != nil {
                fmt.Println("执行请求失败:", err)
                return
        }
        defer resp.Body.Close()

        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
                fmt.Println("读取响应失败:", err)
                return
        }

        fmt.Println("页面长度:", len(body))
        saveHTML(body)

        // 检测页面信息
        if asin := "B0CR919N3T"; string(body) != "" && string(body) != asin {
                fmt.Println("在 Amazon 搜索结果页未找到关键词,发送警告")
        } else {
                fmt.Println("在 Amazon 搜索结果页找到了关键词")
        }
}

func main() {
    monitorAmazon()
}

很神奇的是,你会发现 Golang 这个脚本就可以获取到正确的页面。

这也太奇怪了,都是相同的 IP,说明和 IP 没有关系。

所以就打算用抓包工具抓两个脚本的请求明细,看看是否存在区别。

先在 Python 脚本中,增加了代理,抓包如下:

很神奇的是,直接执行脚本,返回内容只有长度为 2671 的变狗页面。

但通过抓包工具代理执行后,竟然能返回正常的页面。

差别在哪里呢?

仔细查看了抓包请求头信息和自己设置的请求头信息,完全一样,没差别。

那唯一的差别就是抓包工具代理了 HTTP 请求,抓包工具用了自己的 HTTP 请求包。

也就是说,唯一的差别就是 HTTP 客户端有差别。

这一下有了思路。

把 python 脚本使用地 requests 包替换成其他 http 工具包。

试了 urllib3、aiohttp。

我发现用 urllib3 和 request 包请求是一样地问题,一查才知道,requests 包底层处理 HTTP 请求时,就是用的urllib3,所以这两个 http 客户端工具包,本质上是同源的。

换成 aiohttp,瞬间,一切正常,不用加 IP 代理,保持源代码,只是换一个 http 工具包而已。

完整代码如下:

import aiohttp
import asyncio
import os
import time

def save_html(content):
    # 确保目录存在
    directory = "page"
    if not os.path.exists(directory):
        os.makedirs(directory)

    # 生成文件名
    filename = time.strftime("%Y%m%d%H%M%S") + ".html"
    filepath = os.path.join(directory, filename)

    # 保存文件
    with open(filepath, 'w', encoding='utf-8') as file:
        file.write(content)
    print("页面已保存至:", filepath)

async def monitor_amazon():
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "Accept-Encoding": "gzip, deflate, br, zstd",
        "Connection": "keep-alive",
        "Host": "www.amazon.com",
        "Pragma": "no-cache",
        "Cache-Control": "no-cache",
        "device-memory": "8",
        "sec-ch-device-memory": "8",
        "dpr": "1",
        "sec-ch-dpr": "1",
        "viewport-width": "1287",
        "sec-ch-viewport-width": "1287",
        "rtt": "250",
        "downlink": "10",
        "ect": "4g",
        "sec-ch-ua": '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"',
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": '"Windows"',
        "sec-ch-ua-platform-version": '"15.0.0"',
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-User": "?1",
        "Sec-Fetch-Dest": "document",
        "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6",
        "Cookie": "xxx",   # 直接从你设置邮编后的亚马逊网页 F12 查看获取
    }

    # 监控的产品,搜索词
    keyword = "cat litter"
    asin = "B0CR919N3T"
    search_url = f"https://www.amazon.com/s?k={keyword.replace(' ', '+')}"

    async with aiohttp.ClientSession() as session:
        response = await session.get(search_url, headers=headers)
        html = await response.text()
        await session.close()
        save_html(html)
        if "dogs of amazon" in html.lower():
            print("搜索被标识为异常访问")
        elif asin.lower() in html.lower():
            print("在 Amazon 搜索结果页找到了关键词")
        else:
            print("在 Amazon 搜索结果页未找到 ASIN 关键词,发送警告")


# 在 Windows 中使用 SelectorEventLoop
if __name__ == '__main__':
    if os.name == 'nt':
        loop = asyncio.SelectorEventLoop()
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()

    loop.run_until_complete(monitor_amazon())
    loop.close()

能正常获取页面后,剩下的问题就要根据场景来处理。

如果你获取的频率很高,每分钟要获取好几次,那就必须引入动态 IP 代理。

如果频率很低,如果时保护自己产品不被恶意投诉下架,如代码示例判断产品是否还正常存在,那 10 分钟查一次就够了,这种频率,单个 IP 也没问题。

希望对你有帮助。

顺手点个收藏+赞呗~

 

标签:Set,Python,req,爬虫,ch,Header,源码,sec,html
From: https://blog.csdn.net/createNo_1/article/details/141903815

相关文章

  • How to draw a simple relation graph in Python
    forward:https://martinlwx.github.io/en/how-to-draw-a-simple-relation-graph-in-python/ IntroTheprocessofdrawingasimplerelationgraphinpythoncanbebrokendowninto2steps.Defineagraph.Drawagraph.Step1.DefineagraphInthisstep,......
  • python遍历之批量更改文件名
    遍历方式更改文件名importosimportsys#定义一个名字叫做rename的函数defrename(filePath):"""批量重命名指定路径下的'.dbf','.prj','.shp','.shx'格式的文件,重命名格式:文件_文件夹名字,并删除'.sbn','.sbx','.......
  • 【Python】数据可视化之分类图
    目录条形图箱形图散点图分簇散点图小提琴分簇小提琴条形图条形图是一种直观的图表形式,它通过不同长度的矩形条(即“条形”)来展示数值变量的中心趋势估计值,其中每个矩形的高度直接对应于该组数据的某个中心量度(如均值、中位数等)。此外,为了向观众传达关于这些中心趋势估......
  • Python监控进程资源占用并发送邮件
    项目新特性上线后,有时会因为包含内存泄露的问题导致服务资源被占满,以至于线上服务崩溃。最简单的方式是对服务期CPU/内存占用进行监测和及时预警。python中pyutil包是自动化运维常用的工具库之一,可以进行方便获取服务器CPU/内存及进程等相关信息。安装方法pipinstallpsutil......
  • 爬虫转型测试的心得分享
    一:那些爬虫知识可以留下,在测试中进行使用1、请求方式-请求头-响应头get请求与post请求的理解:最大的区别在于:get请求的参数跟在url地址后,而post请求需要提交参数表单在浏览器的开发者工具中的负载下的参数,就是post请求需要的参数信息2、请求头这些内容需要理解这些是......
  • Linux源码下生成并安装内核文档
    最近想使用man命令查看Linux内核函数的帮助信息,无奈有如下提示: xinu@slam:~$manprintkNomanualentryforprintk 而在Linux内核源码下,我们执行makehelp命令后,输出的提示内容有关于内核文档的如下信息:Documentationtargets: Linuxkernelinternaldocumentati......
  • 【Python类型推断】
    在Python中,类型推断是指根据变量所赋的值自动确定变量的数据类型。Python是一种动态类型语言,解释器会在运行时根据赋值操作来推断变量的类型。常见的用于类型推断的方法有type()和isinstance()。例如:num=10print(type(num))#<class'int'>pi=3.14159prin......
  • 基于python+flask框架的校园二手车交易系统(开题+程序+论文) 计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育事业的蓬勃发展,校园内的学生群体日益庞大,他们的消费需求也日益多样化。在校园生活中,学生们常常面临着新旧物品更替的需求,尤其......
  • 基于python+flask框架的求职招聘管理系统(开题+程序+论文) 计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景在当今快速发展的信息化时代,人力资源管理已成为企业核心竞争力的重要组成部分。随着就业市场的日益扩大和求职需求的不断增长,传统的手工或......
  • JSP街道疫情防控物资调配系统h8rp2(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统功能:用户,物资类型,物资信息,物资申请,物资入库,物资调配技术要求:开发语言:JSP前端使用:HTML5,CSS,JSP动态网页技术后端使用SpringBoot,Spring技术主数据......