【问题标题】:Making custom requests using Python Requests使用 Python 请求发出自定义请求
【发布时间】:2019-10-06 20:36:44
【问题描述】:

这是 url https://www.lowes.com/store/AK-Anchorage/2955 当我们到达这个 url 有一个按钮名称“Shop this store”如果我们点击按钮点击按钮和使用链接发出的请求是相同的,但在点击之后仍然按钮一会获得不同的页面,然后直接使用链接。我需要发出与按钮发出的相同请求。

我需要向“https://www.lowes.com/store/AK-Anchorage/2955”发出请求,然后我需要发出与单击按钮相同的请求。

我已尝试连续两次发出请求以获得所需的页面,但没有成功。

url='https://www.lowes.com/store/AK-Anchorage/2955'
ua = UserAgent()
header = {'User-Agent':str(ua.chrome)}
response = requests.get(url, headers=header)
response = requests.get(url, headers=header)

【问题讨论】:

  • 嗯,这个有点棘手。它在 GET 请求到您想要的实际页面之前发出一个 POST 请求(如果您将一个包含到akstat.io ,则为 2 个)。您可能想要使用requests.Session。您需要通过堆栈跟踪和读取 JavaScript 来复制 POST 有效负载。或者,这可能是Selenium 的工作。
  • 请您解释一下我正在使用该会话以及您能否查看链接,这两个请求是否与我提到的相同,我不想使用硒,因为它会变慢过程。
  • 我想发出与按钮使用 python 请求模块相同的请求,当然先请求商店链接。
  • @GordonAitchJay.
  • 当我说它分页 2 个 POST 请求时我犯了错误。当我单击页面下方的另一个蓝色“购买这家商店”按钮时,它会这样做。检查我的答案。单击页面中心的蓝色按钮会将您带到同一页面。 2页有什么区别?而且,您真正想从页面中删除什么?

标签: python python-3.x post request python-requests


【解决方案1】:

所以,这似乎有效。我两次都收到200 OK 响应,但内容长度不同。

对于它的价值,在 Firefox 中,当我单击蓝色的“购买此商店”按钮时,它会将我带到看起来完全相同的页面,但没有我刚刚单击的蓝色按钮。在 Chrome(测试版)中,当我单击蓝色按钮时,我会看到一个 403 Access denied 页面。他们的服务器打得不好。您可能很难实现自己想要实现的目标。

如果我在没有标题的情况下调用session.get,我将永远得不到回应。所以他们显然在检查用户代理,可能是 cookie 等。

import requests

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0",
           "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
           "Accept-Language": "en-US,en;q=0.5",
           "Accept-Encoding": "gzip, deflate, br",
           "Upgrade-Insecure-Requests": "1",}

session = requests.Session()

url = "https://www.lowes.com/store/AK-Anchorage/2955"

response1 = session.get(url, headers=headers)
print(response1, len(response1.content))

response2 = session.get(url, headers=headers)
print(response2, len(response2.content))

输出:

<Response [200]> 56282
<Response [200]> 56323

我做了更多的测试。如果您不更改默认 Python 请求中的 user-agent,服务器将超时。即使将其更改为"" 似乎也足以让服务器给您响应。

您无需选择特定商店即可获取产品信息,包括描述、规格和价格。看看这个 GET 请求,没有 cookie,也没有会话:

import requests, json

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"}

url = "https://www.lowes.com/pd/Google-Nest-Learning-Thermostat-3rd-Gen-Thermostat-and-Room-Sensor-with-with-Wi-Fi-Compatibility/1001080012"

r = requests.get(url, headers=headers, timeout=5)
print("return code:", r)
print("content length:", len(r.content))

for line in r.text.splitlines():
    if "window.digitalData.products = [" in line:
        print("This line includes the 'sellingPrice' and the 'retailPrice'. After some splicing, we can treat it as JSON.")
        left = line.find(" = ") + 3
        right = line.rfind(";")
        print(json.dumps(json.loads(line[left:right]), indent=True))
        break

输出:

return code: <Response [200]>
content length: 107134
This line includes the 'sellingPrice' and the 'retailPrice'. After some splicing, we can treat it as JSON.
[
 {
  "productId": [
   "1001080012"
  ],
  "productName": "Nest_Learning_Thermostat_3rd_Gen_Thermostat_and_Room_Sensor_with_with_Wi-Fi_Compatibility",
  "ivm": "753160-83910-T3007ES",
  "itemNumber": "753160",
  "vendorNumber": "83910",
  "modelId": "T3007ES",
  "type": "ANY",
  "brandName": "Google",
  "superCategory": "Heating & Cooling",
  "quantity": 1,
  "sellingPrice": 249,
  "retailPrice": 249
 }
]

产品描述和规格可以在这个元素中找到:

<section class="pd-information met-product-information grid-100 grid-parent v-spacing-jumbo">

(大约 300 行,所以我只是复制父标签。)

有一个 API 接受产品 ID 和商店编号,并返回定价信息:

import requests, json

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"}

url = "https://www.lowes.com/PricingServices/price/balance?productId=1001080012&storeNumber=1955"

r = requests.get(url, headers=headers, timeout=5)
print("return code:", r)
print("content length:", len(r.content))
print(json.dumps(json.loads(r.text), indent=True))

输出:

return code: <Response [200]>
content length: 768
[
 {
  "productId": 1001080012,
  "storeNumber": 1955,
  "isSosVendorDirect": true,
  "price": {
   "selling": "249.00",
   "retail": "249.00",
   "typeCode": 1,
   "typeIndicator": "Regular Price"
  },
  "availability": [
   {
    "availabilityStatus": "Available",
    "productStockType": "STK",
    "availabileQuantity": 822,
    "deliveryMethodId": 1,
    "deliveryMethodName": "Parcel Shipping",
    "storeNumber": 907
   },
   {
    "availabilityStatus": "Available",
    "productStockType": "STK",
    "availabileQuantity": 8,
    "leadTime": 1570529161540,
    "deliveryMethodId": 2,
    "deliveryMethodName": "Store Pickup",
    "storeNumber": 1955
   },
   {
    "availabilityStatus": "Available",
    "productStockType": "STK",
    "availabileQuantity": 1,
    "leadTime": 1570529161540,
    "deliveryMethodId": 3,
    "deliveryMethodName": "Truck Delivery",
    "storeNumber": 1955
   }
  ],
  "@type": "item"
 }
]

它可以包含多个产品编号。例如: https://www.lowes.com/PricingServices/price/balance?productId=1001080046%2C1001135076%2C1001091656%2C1001086418%2C1001143824%2C1001094006%2C1000170557%2C1000920864%2C1000338547%2C1000265699%2C1000561915%2C1000745998&storeNumber=1564


您可以使用这个返回 1.6MB json 文件的 API 获取每个商店的信息。 maxResults 通常设置为30query 是您的经度和纬度。我建议将其保存到磁盘。我怀疑它改变了很多。

https://www.lowes.com/wcs/resources/store/10151/storelocation/v1_0?maxResults=2000&query=0%2C0

请记住,PricingServices/price/balance 端点可以为 storeNumber 采用多个值,以 %2C(逗号)分隔,因此您不需要 1763 个单独的 GET 请求。我仍然使用requests.Session 发出多个请求(因此它重用了底层连接)。

【讨论】:

  • 感谢您的回复,实际上是在使用链接直接到达商店然后单击搜索按钮之后,如果我将直接链接到产品,例如“lowes.com/pd/…”,我会得到产品列表到达商店后使用链接并按下商店此按钮的特定商店。如果我不按“购买此”商店并使用链接直接搜索产品,我将无法获得该特定商店的产品列表。
  • 我需要抓取产品信息,当我到达商店后点击“shop this”按钮时,如果我直接请求产品链接,我只能从该商店获取产品信息,有多个商店,但是指向产品列表的链接是相同的,当我们单击购买此商店按钮并搜索产品链接时,我们会获得特定于该商店的产品信息。
  • 我打开network monitor浏览了他们的网站,记录了所有的请求。然后我浏览了它是否有任何有趣的东西。我找到了一种获取每个商店 ID 的方法(总共 1763 个)。向PricingServices/price/balance 端点发出 GET 请求,我发现 12 种产品中的 5 种(我在答案中链接到的)在某些商店更便宜。这具体是您所追求的信息吗?你关心其他信息吗?你还需要什么? (我再次使用 API 更新了我的答案以获取每个商店 ID)
  • 是的,this endpoint 返回每​​个商店的信息,包括商店 ID。正如我在回答中解释的那样,使用(这个其他端点)[lowes.com/PricingServices/price/… 来获取特定商店中特定产品的价格。 productIdstoreNumber 都采用多个值,以 %2C 分隔。如果您每次输入 20 个商店编号,则只需约 90 个请求,而不是 1763 个。
  • 我不能保证任何特定的学习资源,但你需要熟悉这些东西:操作/迭代/访问lists 和dicts,并创建一个dict使用json 模块或requests 响应对象的json() 方法。
【解决方案2】:

这取决于您想对数据做什么。在 URL 中您已经有商店 ID。

单击按钮时,它会向https://www.lowes.com/store/api/2955 发出请求以获取商店信息。是你要找的吗?

如果是这样,您不需要 2 个请求,而只需一个请求即可获取所需的商店信息。

【讨论】:

  • 感谢您的回复,实际上在使用链接直接到达商店然后单击搜索按钮之后,如果我将直接链接到产品,例如“lowes.com/pd/…”,我会得到产品列表到达商店后使用链接并按下商店此按钮的特定商店。如果我不按“购买此”商店并使用链接直接搜索产品,我将无法获得该特定商店的产品列表。
  • 我需要抓取产品信息,当我到达商店后点击“shop this”按钮时,如果我直接请求产品链接,我只能从该商店获取产品信息,有多个商店,但是指向产品列表的链接是相同的,当我们单击购买此商店按钮并搜索产品链接时,我们会获得特定于该商店的产品信息。
  • 我需要通过请求复制此浏览器行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-05
  • 2017-11-28
  • 2013-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多