簡體   English   中英

無法從網頁上抓取所有公司名稱

[英]Can't scrape all the company names from a webpage

我正在嘗試解析此網頁中的所有公司名稱。 那里大約有2431家公司。 但是,我在下面嘗試的方式可以獲取1000結果。

這是我在使用開發工具時看到的響應結果數量:

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

如何使用請求獲取結果的 rest?

到目前為止我已經嘗試過:

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']))

作為一種解決方法,您可以使用字母表作為搜索模式來模擬搜索。 使用下面的代碼,您將獲得所有 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))

2021 年 1 月 4 日更新

在查看了 Algolia API 文檔中的“細則”后,我發現在查詢中不能使用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 文檔,查詢命中限制為 1000。

該文檔列出了幾種覆蓋或繞過此限制的方法。

API 的一部分是paginationLimitedTo ,默認情況下設置為 1000 以實現性能和“刮擦保護”。

語法是:

'paginationLimitedTo': number_of_records

文檔中提到的另一種方法是設置參數偏移量長度。

偏移量讓您指定起始命中(或記錄)

length設置返回的記錄數

您可以使用這些參數來遍歷記錄,因此可能不會影響您的抓取性能。

例如,您可以以 500 個為單位進行刮削。

  • 記錄 1-500(偏移量=0,長度=500)
  • 記錄 501-1001(偏移量=500,長度=500)
  • 記錄 1002-1502(偏移量=1001,長度=500)
  • ETC...

或者

  • 記錄 1-500(偏移量=0,長度=500)
  • 記錄 500-1000(偏移量=499,長度=500)
  • 記錄 1000-1500(偏移量=999,長度=500)
  • ETC...

后一種會產生一些重復,當將它們添加到內存存儲(列表、字典、數據框)時可以很容易地刪除它們。

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

嘗試在負載中顯式limit值以覆蓋 API 默認值。 例如,將limit=2500插入到您的請求字符串中。

看起來您需要像這樣設置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

還有其他方法可以解決這個問題。 首先,您可以添加&filters=objectID:SomeIds
Algolia 允許您在一個請求中發送 1000 個不同的查詢 該主體將返回給您兩個對象:
{"requests":[{"indexName":"YCCompany_production","params":"hitsPerPage=1000&query&filters=objectID:271"}, {"indexName":"YCCompany_production","params":"hitsPerPage=1000&query&filters=objectID:5"}]}
您可以檢查 objectID 值。 1-30000 的范圍在哪里。 只需發送 1-30000 之間的隨機 objectID,只需 30 個請求,您將獲得所有 3602 個公司。

這是我的 java 代碼:

    public static void main(String[] args) throws IOException {
        System.out.println("Start scraping content...>> " + new Timestamp(new Date().getTime()));
        Set<Integer> allIds = new HashSet<>();
        URL target = new URL("https://45bwzj1sgc-dsn.algolia.net/1/indexes/*/queries?x-algolia-agent=Algolia%20for%20JavaScript%20(3.35.1)%3B%20Browser%3B%20JS%20Helper%20(3.7.0)&x-algolia-application-id=45BWZJ1SGC&x-algolia-api-key=Zjk5ZmFjMzg2NmQxNTA0NGM5OGNiNWY4MzQ0NDUyNTg0MDZjMzdmMWY1NTU2YzZkZGVmYjg1ZGZjMGJlYjhkN3Jlc3RyaWN0SW5kaWNlcz1ZQ0NvbXBhbnlfcHJvZHVjdGlvbiZ0YWdGaWx0ZXJzPSU1QiUyMnljZGNfcHVibGljJTIyJTVEJmFuYWx5dGljc1RhZ3M9JTVCJTIyeWNkYyUyMiU1RA%3D%3D");
        String requestBody = "{\"requests\":[{\"indexName\":\"YCCompany_production\",\"params\":\"hitsPerPage=1000&query&filters=objectID:24638\"}]}";
        int index = 1;
        List<String> results = new ArrayList<>();
        String bodyIndex = "{\"indexName\":\"YCCompany_production\",\"params\":\"hitsPerPage=1000&query&filters=objectID:%d\"}";
        for (int i = 1; i <= 30; i++) {
            StringBuilder body = new StringBuilder("{\"requests\":[");
            for (int j = 1; j <= 1000; j++) {
                body.append(String.format(bodyIndex, index));
                body.append(",");
                index++;
            }
            body = new StringBuilder(body.substring(0, body.length() - 1));
            body.append("]}");
            HttpURLConnection con = (HttpURLConnection) target.openConnection();
            con.setDoOutput(true);
            con.setRequestMethod(HttpMethod.POST.name());
            con.setRequestProperty(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON);
            OutputStream os = con.getOutputStream();
            os.write(body.toString().getBytes(StandardCharsets.UTF_8));
            os.close();
            con.connect();
            String response = new String(con.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
            results.add(response);
        }
        results.forEach(result -> {
            JsonArray array = JsonParser.parseString(result).getAsJsonObject().get("results").getAsJsonArray();
            array.forEach(data -> {
                if (((JsonObject) data).get("nbHits").getAsInt() == 0) {
                    return;
                } else {
                    allIds.add(((JsonObject) data).get("hits").getAsJsonArray().get(0).getAsJsonObject().get("id").getAsInt());
                }
            });
        });
        System.out.println("Total scraped ids " + allIds.size());
        System.out.println("Finish scraping content...>>>> " + new Timestamp(new Date().getTime()));
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM