【问题标题】:BeautifulSoup web scraping for a webpage where information is obtained after clicking a buttonBeautifulSoup 网页抓取,用于点击按钮后获取信息的网页
【发布时间】:2021-04-26 12:31:44
【问题描述】:

所以,我正在尝试获取一些餐馆的 Yelp 页面的“设施和更多”部分。问题是我可以从首先显示的餐厅的 Yelp 页面访问设施。但是,它具有“n more”按钮,单击该按钮可提供更多便利。将 BeautifulSoup 和 selenium 与网页 url 一起使用以及将 BeautifulSoup 与请求一起使用会得到完全相同的结果,我不知道如何在我的代码中获取它们之前打开整个设施。下面的两张图片显示了单击按钮之前和之后发生的情况。

  1. “在点击“5 更多属性”之前:第一张图片显示了 4 个“div”,其中包含“span”,我可以使用上述任何一种方法。
  2. “点击“5 更多属性”后:第二张图片显示了 9 个“div”,其中包含我想要到达的“span”。

这是使用 selenium/beautifulsoup 的代码

import selenium
from selenium import webdriver
from bs4 import BeautifulSoup

URL ='https://www.yelp.com/biz/ziggis-coffee-longmont'

driver = 
 webdriver.Chrome(r"C:\Users\Fariha\AppData\Local\Programs\chromedriver_win32\chromedriver.exe")
driver.get(URL)
yelp_page_source_page1 = driver.page_source



soup = BeautifulSoup(yelp_page_source_page1,'html.parser')
spans = soup.find_all('span')

结果:“spans”中有 990 个元素。我只显示与我的问题相关的内容:

【问题讨论】:

  • 注意:不要将变量命名为all。这将覆盖名为 all() 的内置函数。

标签: python html selenium web-scraping beautifulsoup


【解决方案1】:

另一种方法是直接从网站上的 JSON api 提取数据。这可以在没有 selenium 开销的情况下完成,如下所示:

from bs4 import BeautifulSoup
import requests
import json

session = requests.Session()
r = session.get('https://www.yelp.com/biz/ziggis-coffee-longmont')
#r = session.get('https://www.yelp.com/biz/menchies-frozen-yogurt-lafayette')

soup = BeautifulSoup(r.content, 'lxml')

# Locate the business ID to use (from JSON inside one of the script entries)
for script in soup.find_all('script', attrs={"type" : "application/json"}):
    gaConfig = json.loads(script.text.strip('<!-->'))

    try:
        biz_id = gaConfig['gaConfig']['dimensions']['www']['business_id'][1]
        break
    except KeyError:
        pass

# Build a suitable JSON request for the required information
json_post = [
    {
        "operationName": "GetBusinessAttributes",
        "variables": {
            "BizEncId": biz_id
        },
        "extensions": {
            "documentId": "35e0950cee1029aa00eef5180adb55af33a0217c64f379d778083eb4d1c805e7"
        }
    },
    {
        "operationName": "GetBizPageProperties",
        "variables": {
            "BizEncId": biz_id
        },
        "extensions": {
            "documentId": "f06d155f02e55e7aadb01d6469e34d4bad301f14b6e0eba92a31e635694ebc21"
        }
    },
]

r = session.post('https://www.yelp.com/gql/batch', json=json_post)
j = r.json()

business = j[0]['data']['business']
print(business['name'], '\n')

for property in j[1]['data']['business']['organizedProperties'][0]['properties']:
    print(f'{"Yes" if property["isActive"] else "No":5} {property["displayText"]}')

这将为您提供以下条目:

Ziggi's Coffee 

Yes   Offers Delivery
Yes   Offers Takeout
Yes   Accepts Credit Cards
Yes   Private Lot Parking
Yes   Bike Parking
Yes   Drive-Thru
No    No Outdoor Seating
No    No Wi-Fi

这是如何解决的?

您最好的朋友是您浏览器的网络开发工具。有了这个,您可以查看为获取信息而提出的请求。正常的流程是下载初始 HTML 页面,这会运行 javascript 并请求更多数据以进一步填充页面。

诀窍是首先找到您想要的数据的位置(通常以 JSON 形式返回),然后确定您需要什么来重新创建发出请求所需的参数。

要进一步了解此代码,请使用print()。打印所有内容,它将向您展示每个部分如何构建下一个部分。这就是脚本的编写方式,一次一点。

使用 Selenium 的方法允许 javascript 工作,但大多数时候不需要这样做,因为它只是发出请求并格式化数据以供显示。

【讨论】:

  • 谢谢马丁。非常感谢。现在,由于我对 python 和网络报废非常陌生,您能否推荐任何我可以阅读或观看的资源来理解代码。它工作正常,但我也想了解它。例如,我知道 'find_all' 做了什么,但 "attrs={"type" : "application/json"}" 做了什么。你是怎么想出 json_post 的 documentID 的?等
  • 我已经更新了解释以提供帮助。 attrs 部分允许您仅匹配包含指定属性的标签。如果您查看源 HTML,您将看到带有各种参数的 &lt;script&gt; 标记,这有助于只关注包含 JSON 的条目。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-04
  • 1970-01-01
  • 2015-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多