Google 中的结果数量错误 Python

Wrong number of results in Google Scrape with Python

我正在尝试学习网络抓取,但我遇到了一个奇怪的问题...我的任务是搜索 Google 特定日期范围内某个主题的新闻并计算结果数。

我的简单代码是

import requests,  bs4

payload = {'as_epq': 'James Clark', 'tbs':'cdr:1,cd_min:1/01/2015,cd_max:1/01/2015','tbm':'nws'}    
r = requests.get("https://www.google.com/search", params=payload)

soup = bs4.BeautifulSoup(r.text)
elems = soup.select('#resultStats')
print(elems[0].getText())

我得到的结果是

About 8,600 results

所以显然所有的工作...除了结果是错误的。如果我在 Firefox 中打开 URL(我可以用 r.url 获得完整的 URL)

https://www.google.com/search?tbm=nws&as_epq=James+Clark&tbs=cdr%3A1%2Ccd_min%3A1%2F01%2F2015%2Ccd_max%3A1%2F01%2F2015

我看到结果其实是只有2,如果我手动下载HTML文件,打开页面源搜索 id="resultStats" 我发现结果数确实是2个!

谁能帮我理解为什么在保存的 HTML 文件和 soup 项目中搜索相同的 id 标签会导致两个不同的数值结果?

*************** 更新 问题似乎是 requests.get 没有正确处理自定义日期范围。如果我将相同的 URL 与 selenium 一起使用,我会得到正确的答案

from selenium import webdriver
driver = webdriver.Firefox()
driver.get(url)
content = driver.page_source
soup = bs4.BeautifulSoup(content)
elems = soup.select('#resultStats')
print(elems[0].getText())

答案是

2 results (0.09 seconds) 

问题是这个方法好像比较麻烦,因为我需要在Firefox中打开页面...

有几件事导致了这个问题。首先,它需要 2 位数字的日期和月份部分,并且还需要一些流行浏览器的用户代理字符串。以下代码应该有效:

import requests,  bs4

headers = {
    "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36"
}
payload = {'as_epq': 'James Clark', 'tbs':'cdr:1,cd_min:01/01/2015,cd_max:01/01/2015', 'tbm':'nws'}
r = requests.get("https://www.google.com/search", params=payload, headers=headers)

soup = bs4.BeautifulSoup(r.content, 'html5lib')
print soup.find(id='resultStats').text

添加到 Vikas 的回答中,Google 也将无法对某些用户代理使用 'custom date range'。也就是说,对于某些用户代理,Google 将只搜索 'recent' 结果而不是您指定的日期范围。

我没有检测到用户代理会打破自定义日期范围的明确模式。似乎包括语言是一个因素。

以下是一些破坏 cdr 的用户代理示例:

Mozilla/5.0 (Windows; U; Windows NT 6.1; fr-FR) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27

Mozilla/4.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/5.0)

selenium不需要,你要找的是:

soup.select_one('#result-stats nobr').previous_sibling
# About 10,700,000 results

代码和full example in the online IDE:

from bs4 import BeautifulSoup
import requests, lxml

headers = {
    "User-Agent":
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19582"
}

params = {
    "q": 'James Clark',  # query
    "hl": "en",          # lang
    "gl": "us",          # country to search from
    "tbm": "nws",        # news filter
}

html = requests.get('https://www.google.com/search', headers=headers, params=params)
soup = BeautifulSoup(html.text, 'lxml')

# if used without "nobr" selector and previous_sibling it will return seconds as well: (0.41 secods)
number_of_results = soup.select_one('#result-stats nobr').previous_sibling
print(number_of_results)

# About 10,700,000 results

或者,您可以使用 SerpApi 中的 Google News Results API 来实现相同的目的。这是付费 API 和免费计划。

你的情况的不同之处在于你不必找到哪些选择器可以完成工作,或者弄清楚为什么其中一些不return你想要的数据他们也应该绕过阻止搜索引擎,并随着时间的推移维护它。

相反,您只需要迭代结构化 JSON 并快速获取您想要的数据。

为您的案例集成的代码:

import os
from serpapi import GoogleSearch

params = {
  "engine": "google",
  "q": 'James Clark',
  "tbm": "nws",
  "gl": "us",
  "api_key": os.getenv("API_KEY"),
}

search = GoogleSearch(params)
results = search.get_dict()

number_of_results = results['search_information']['total_results']
print(number_of_results)

# 14300000

Disclaimer, I work for SerpApi.