【问题标题】:Increasing speed of a loop where intervals are small and requesting larger amount of data at once在间隔很小并一次请求大量数据的情况下提高循环的速度
【发布时间】:2021-06-29 17:13:23
【问题描述】:

所以下面的代码是假设穿越加拿大并获取 Circle K 的位置。
我要去 0.0001 因为事实上,像多伦多这样的城市的商店很密集,当检查 lat&lng 时下降到 4 sig。
当我运行代码时,我注意到一次检查 0.0001 需要很长时间才能以一种方式检查大约 42 的范围。
此外,当我运行代码时,我将连续获得相同的位置,因为区域差异为 0.0001,几乎没有商店不会导致发现任何新商店。
重复和慢磨的结合是我要问是否有人对如何加快这个过程有一些建议。
我正在考虑在 url 末尾添加 : &page=100 ,但这无济于事,因为代码只是将它视为第 100 页的内容输出,其中不包含之前的 99 页。
有没有办法一次输出 0-whatever 页面之间的页面?
我也包含了当前代码,以防我忽略了简单的修复。

因此,目标是一次请求更多数据并更快地扫描整个加拿大。

我的代码:

import requests
import json
import numpy as np
import csv 

lat_lng = [(lat,long) for lat,long in zip(np.arange(42,84,0.01),np.arange(-142,-52,0.01))] 

for latitude,longitude in lat_lng:
  url = f"https://www.circlek.com/stores_new.php?lat={latitude}&lng={longitude}&services=&region=global"
  payload={}
  headers = {
    'Connection': 'keep-alive',
    'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
    'Accept': '*/*',
    'X-Requested-With': 'XMLHttpRequest',
    'sec-ch-ua-mobile': '?0',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Dest': 'empty',
    'Referer': 'https://www.circlek.com/store-locator?Canada&lat=43.6529&lng=-79.3849',
    'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8',
    'dnt': '1'
  }

  response = requests.request("GET", url, headers=headers, data=payload)

  print(response.json())

还有当我添加页面时 url 的外观:https://www.circlek.com/stores_new.php?lat={latitude}&lng={longitude}&services=&region=global&page=1

我觉得找到一种抓取多个页面的方法是可行的方法,但没有真正的方法。

提前致谢!

【问题讨论】:

  • 请编辑段落以使其可读。考虑向朋友或老板提出这个问题。他们必须能够理解你想要什么。
  • 如果我理解的话,你应该在你正在使用的 API 中查找分页。

标签: python web-scraping python-requests pagination


【解决方案1】:

问题是,你一个接一个地做 4200 请求。 我已经重写了您的程序以异步执行它,这大大加快了它的速度。您必须安装 httpx 库才能使其正常工作。 这是修改后的代码:

import json
import numpy as np
import csv
import httpx
import asyncio

async def print_data():
    lat_lng = [
        (lat, long) for lat, long in zip(np.arange(42, 84, 0.01), np.arange(-142, -52, 0.01))
    ]
    urls = [
        f"https://www.circlek.com/stores_new.php?lat={la}&lng={lo}&services=&region=global"
        for la, lo in lat_lng
    ][:100] # Only the first 100 urls are requested here!!
    headers = {
        "Connection": "keep-alive",
        "sec-ch-ua": '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
        "Accept": "*/*",
        "X-Requested-With": "XMLHttpRequest",
        "sec-ch-ua-mobile": "?0",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Dest": "empty",
        "Referer": "https://www.circlek.com/store-locator?Canada&lat=43.6529&lng=-79.3849",
        "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
        "dnt": "1",
    }
    async with httpx.AsyncClient() as c:
        tasks = (c.get(url, headers=headers) for url in urls)
        resp = await asyncio.gather(*tasks)
    for r in resp:
        print(r.json())


if __name__ == "__main__":
    asyncio.run(print_data())

在我的示例中,我只请求了前 100 个 url,因为服务器不会在短时间内响应那么多请求。 (阅读速率限制,如果你不知道的话)。 因此,您仍然必须实施某种限制,以减少您每秒发送的请求。 (也许分批做几百个,然后在它们之间睡一会儿)。

【讨论】:

  • 所以,我做了 pip instal httpx 并将代码复制并粘贴到 python 中。但是,在输出窗口中没有显示任何内容。有什么我错过的吗?
  • @John_Muir 它应该打印出 json 结果。程序是否返回状态码 0?您是否复制了以if __name__ == "__main__": 开头的最后两行?它们隐藏在卷轴后面。
  • 哦,等待它现在开始工作,也许我之前错过了那部分。为了收集数据,我只是更改显示 100 的位置还是有其他方法。
  • @John_Muir 如果您从行尾删除 [:100],它将异步请求所有 4200 个页面(而不是前 100 个)。问题是服务器不会在一大块之后响应,如果你这样做,你会得到超时错误。因此,您应该将 url 分成更小的块,并可能在这些块之间睡一会儿。具体如何进行速率限制取决于您。
猜你喜欢
  • 1970-01-01
  • 2021-09-26
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 2015-03-24
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
相关资源
最近更新 更多