无法从网页中抓取所有公司名称

Posted

技术标签:

【中文标题】无法从网页中抓取所有公司名称【英文标题】:Can't scrape all the company names from a webpage 【发布时间】:2021-04-08 03:51:53 【问题描述】:

我正在尝试解析此 webpage 中的所有公司名称。那里有大约2431 公司。但是,我在下面尝试的方式可以让我获得1000 结果。

这是我在使用开发工具时看到的响应结果数量:

hitsPerPage: 1000
index: "YCCompany_production"
nbHits: 2431      <------------------------       
nbPages: 1
page: 0

如何使用请求获得其余结果?

到目前为止我已经尝试过:

import requests

url = 'https://45bwzj1sgc-dsn.algolia.net/1/indexes/*/queries?'

params = 
    'x-algolia-agent': 'Algolia for javascript (3.35.1); Browser; JS Helper (3.1.0)',
    'x-algolia-application-id': '45BWZJ1SGC',
    'x-algolia-api-key': 'NDYzYmNmMTRjYzU4MDE0ZWY0MTVmMTNiYzcwYzMyODFlMjQxMWI5YmZkMjEwMDAxMzE0OTZhZGZkNDNkYWZjMHJlc3RyaWN0SW5kaWNlcz0lNUIlMjJZQ0NvbXBhbnlfcHJvZHVjdGlvbiUyMiU1RCZ0YWdGaWx0ZXJzPSU1QiUyMiUyMiU1RCZhbmFseXRpY3NUYWdzPSU1QiUyMnljZGMlMjIlNUQ='

payload = "requests":["indexName":"YCCompany_production","params":"hitsPerPage=1000&query=&page=0&facets=%5B%22top100%22%2C%22isHiring%22%2C%22nonprofit%22%2C%22batch%22%2C%22industries%22%2C%22subindustry%22%2C%22status%22%2C%22regions%22%5D&tagFilters="]

with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
    r = s.post(url,params=params,json=payload)
    print(len(r.json()['results'][0]['hits']))

【问题讨论】:

提取总计数然后循环直到到达发出请求同时更改页面参数值。分页限制似乎是 1000,覆盖是服务器端设置。不知道offset and length 有什么限制。 许多 AP (如果不是大多数)限制了一个请求返回的条目数量。在这些情况下,您必须使用偏移量并执行多个请求 【参考方案1】:

作为一种解决方法,您可以使用字母作为搜索模式来模拟搜索。使用下面的代码,您将获得所有 2431 家公司作为字典,其中 ID 作为键,完整的公司数据字典作为值。

import requests
import string

params = 
    'x-algolia-agent': 'Algolia for JavaScript (3.35.1); Browser; JS Helper (3.1.0)',
    'x-algolia-application-id': '45BWZJ1SGC',
    'x-algolia-api-key': 'NDYzYmNmMTRjYzU4MDE0ZWY0MTVmMTNiYzcwYzMyODFlMjQxMWI5YmZkMjEwMDAxMzE0OTZhZGZkNDNkYWZjMHJl'
                         'c3RyaWN0SW5kaWNlcz0lNUIlMjJZQ0NvbXBhbnlfcHJvZHVjdGlvbiUyMiU1RCZ0YWdGaWx0ZXJzPSU1QiUyMiUy'
                         'MiU1RCZhbmFseXRpY3NUYWdzPSU1QiUyMnljZGMlMjIlNUQ='


url = 'https://45bwzj1sgc-dsn.algolia.net/1/indexes/*/queries'
result = dict()
for letter in string.ascii_lowercase:
    print(letter)

    payload = 
        "requests": [
            "indexName": "YCCompany_production",
            "params": "hitsPerPage=1000&query=" + letter + "&page=0&facets=%5B%22top100%22%2C%22isHiring%22%2C%22nonprofit%22%2C%22batch%22%2C%22industries%22%2C%22subindustry%22%2C%22status%22%2C%22regions%22%5D&tagFilters="
        ]
    

    r = requests.post(url, params=params, json=payload)
    result.update(h['id']: h for h in r.json()['results'][0]['hits'])

print(len(result))

【讨论】:

这是解决 OP 问题的巧妙解决方法。在我的书中绝对值得一票,因为你教会了我一些东西。 有效!只需更新 Algolia Api 密钥和 Algolia 代理【参考方案2】:

2021 年 1 月 4 日更新

查看 Algolia API documentation 中的“细则”后,我发现 paginationLimitedTo 参数不能在查询中使用。此参数只能在数据所有者索引期间使用。

看来你可以这样使用查询和偏移:

payload = "requests":["indexName":"YCCompany_production",
                        "params": "query=&offset=1000&length=500&facets=%5B%22top100%22%2C%22isHiring%22%2C%22nonprofit"
                                 "%22%2C%22batch%22%2C%22industries%22%2C%22subindustry%22%2C%22status%22%2C%22regions%22%5D&tagFilters="]

很遗憾,客户设置的 paginationLimitedTo 索引不允许您通过 API 检索超过 1000 条记录。

"hits": [],
    "nbHits": 2432,
    "offset": 1000,
    "length": 500,
    "message": "you can only fetch the 1000 hits for this query. You can extend the number of hits returned via the paginationLimitedTo index parameter or use the browse method. You can read our FAQ for more details about browsing: https://www.algolia.com/doc/faq/index-configuration/how-can-i-retrieve-all-the-records-in-my-index",

提到的浏览绕过方法需要 ApplicationIDAdminAPIKey


原帖

基于 Algolia API documentation,查询命中限制为 1000。

文档列出了几种覆盖或绕过此限制的方法。

API 的一部分是 paginationLimitedTo,默认情况下设置为 1000 以实现性能和“抓取保护”。

语法是:

'paginationLimitedTo': number_of_records

文档中提到的另一个method是设置参数offsetlength。

offset 让您指定起始命中(或记录)

长度设置返回的记录数

您可以使用这些参数来遍历记录,因此可能不会影响您的抓取性能。

例如,您可以以 500 个为单位进行刮削。

记录 1-500(偏移量=0,长度=500) 记录 501-1001(偏移量=500,长度=500) 记录 1002-1502(偏移量=1001,长度=500) 等等……

记录 1-500(偏移量=0,长度=500) 记录 500-1000(偏移量=499,长度=500) 记录 1000-1500(偏移量=999,长度=500) 等等……

后一种会产生一些重复,当将它们添加到内存存储(列表、字典、数据框)时可以很容易地删除它们。

----------------------------------------
My system information
----------------------------------------
Platform:    macOS
Python:      3.8.0
Requests:    2.25.1
----------------------------------------

【讨论】:

绕过限制需要什么很清楚,但在哪里使用它们仍然很模糊。如果我想使用'paginationLimitedTo': number_of_records,我无法理解将它们放在哪里,是在 params 或 payload 还是其他地方? @MITHU 我用其他信息更新了我的答案。【参考方案3】:

看起来您需要像这样设置param 来覆盖默认值。与

   index.set_settings

  'paginationLimitedTo': number_of_records

Pyhton 的使用示例。

 index.set_settings('customRanking': ['desc(followers)'])

更多信息:- https://www.algolia.com/doc/api-reference/api-methods/set-settings/#examples

【讨论】:

【参考方案4】:

尝试在负载中使用显式 limit 值来覆盖 API 默认值。例如,将limit=2500 插入到您的请求字符串中。

【讨论】:

插入任何键,如在负载中的limit=2500 会导致Unknown parameter 响应错误。我想我没有遵循你的建议。谢谢。 你不要把它作为键插入;它是“params”值中的关键字参数。 API 文档告诉您有关设置该限制的哪些内容?

以上是关于无法从网页中抓取所有公司名称的主要内容,如果未能解决你的问题,请参考以下文章

无法使用请求抓取 graphql 页面

无法从网页中抓取产品标题

网页抓取(在 R 中?)

如何用 Python 和 lxml 抓取这个网页?返回空列表

在 selenium 中加速网页抓取

如何抓取网页中的动态数据