【问题标题】:How to retrieve information from a website using Beautiful Soup?如何使用 Beautiful Soup 从网站检索信息?
【发布时间】:2020-12-25 19:26:20
【问题描述】:

我遇到了一项任务,我必须使用爬虫从网站检索信息。 (网址:https://www.onepa.gov.sg/cat/adventure

该网站有多种产品。对于每个产品,它都包含将我们定向到该单个产品网页的链接,我想收集所有链接。

screenshot of the webpage

screenshot of the HTML code

例如,其中一个产品的名称为:KNOTTY STUFF,我希望得到 /class/details/c026829364 的 href

import requests
from bs4 import BeautifulSoup


def get_soup(url):
    source_code = requests.get(url)
    plain_text = source_code.text
    soup = BeautifulSoup(plain_text, features="html.parser")
    return soup

url = "https://www.onepa.gov.sg/cat/adventure"
soup = get_soup(url)
for i in soup.findAll("a", {"target": "_blank"}):
    print(i.get("href"))

输出为https://tech.gov.sg/report_vulnerability https://www.pa.gov.sg/feedback 其中不包括我正在寻找的内容:/class/details/c026829364

感谢任何帮助或帮助,谢谢!

【问题讨论】:

  • 尝试在plain_text中搜索/class/details/c026829364
  • 我会使用scrapy

标签: python beautifulsoup web-crawler


【解决方案1】:

网站是动态加载的,因此requests 不支持。但是,可以通过向以下地址发送POST 请求来获得这些链接:

https://www.onepa.gov.sg/sitecore/shell/WebService/Card.asmx/GetCategoryCard

尝试使用内置的re(正则表达式)模块搜索链接

import re
import requests


URL = "https://www.onepa.gov.sg/sitecore/shell/WebService/Card.asmx/GetCategoryCard"

headers = {
    "authority": "www.onepa.gov.sg",
    "accept": "application/json, text/javascript, */*; q=0.01",
    "x-requested-with": "XMLHttpRequest",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
    "content-type": "application/json; charset=UTF-8",
    "origin": "https://www.onepa.gov.sg",
    "sec-fetch-site": "same-origin",
    "sec-fetch-mode": "cors",
    "sec-fetch-dest": "empty",
    "referer": "https://www.onepa.gov.sg/cat/adventure",
    "cookie": "visid_incap_2318972=EttdbbMDQMeRolY+XzbkN8tR5l8AAAAAQUIPAAAAAAAjkedvsgJ6Zxxk2+19JR8Z; SC_ANALYTICS_GLOBAL_COOKIE=d6377e975a10472b868e47de9a8a0baf; _sp_ses.075f=*; ASP.NET_SessionId=vn435hvgty45y0fcfrold2hx; sc_pview_shuser=; __AntiXsrfToken=30b776672938487e90fc0d2600e3c6f8; BIGipServerpool_PAG21PAPRPX00_443=3138016266.47873.0000; incap_ses_7221_2318972=5BC1VKygmjGGtCXbUiU2ZNRS5l8AAAAARKX8luC4fGkLlxnme8Ydow==; font_multiplier=0; AMCVS_DF38E5285913269B0A495E5A%40AdobeOrg=1; _sp_ses.603a=*; SC_ANALYTICS_SESSION_COOKIE=A675B7DEE34A47F9803ED6D4EC4A8355|0|vn435hvgty45y0fcfrold2hx; _sp_id.603a=d539f6d1-732d-4fca-8568-e8494f8e584c.1608930022.1.1608930659.1608930022.bfeb4483-a418-42bb-ac29-42b6db232aec; _sp_id.075f=5e6c62fd-b91d-408e-a9e3-1ca31ee06501.1608929756.1.1608930947.1608929756.73caa28b-624c-4c21-9ad0-92fd2af81562; AMCV_DF38E5285913269B0A495E5A%40AdobeOrg=1075005958%7CMCIDTS%7C18622%7CMCMID%7C88630464609134511097093602739558212170%7CMCOPTOUT-1608938146s%7CNONE%7CvVersion%7C4.4.1",
}

data = '{"cat":"adventure", "subcat":"", "sort":"", "filter":"[filter]", "cp":"[cp]"}'

response = requests.post(URL, data=data,  headers=headers)
print(re.findall(r"<Link>(.*)<", response.content.decode("unicode_escape")))

输出:

['/class/details/c026829364', '/interest/details/i000027991', '/interest/details/i000009714']

【讨论】:

  • 嗨,我想知道为什么在运行您提供的相同代码时会得到不同的输出。
  • 输出为:['/class/details/c026831851', '/class/details/c026831729', '/class/details/c026831723', '/class/details/c026831728', ' /class/details/c026831722', '/class/details/c026831721', '/class/details/c026831720', '/class/details/c026831718', '/class/details/c026831719', '/class/details/ c026831610', '/class/details/c026831600', '/class/details/c026832480', '/class/details/c026832459', '/class/details/c026831585', '/class/details/c026831572', '/ class/details/c026832456', '/class/details/c026832479', '/class/details/c026832453', '/class/details/c026831154'...
【解决方案2】:

这是因为页面使用dynamic javascript 准备跨度链接。所以你将无法使用普通的requests 来完成它。

相反,您应该使用 selenium 和 webdriver 在抓取之前加载所有链接。

您可以尝试下载 ChromeDriver 可执行文件here。如果将其粘贴到与脚本相同的文件夹中,则可以运行:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import WebDriverException
import os

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--window-size=1920x1080")
chrome_options.add_argument("--headless")
chrome_driver = os.getcwd() + "\\chromedriver.exe"  # CHANGE THIS PATH IF NOT SAME FOLDER
driver = webdriver.Chrome(options=chrome_options, executable_path=chrome_driver)

url = "https://www.onepa.gov.sg/cat/adventure"
driver.get(url)

try:
    # Waint links to be ready
    WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, ".gridTitle > span > a"))
    )
except WebDriverException:
    print("Page offline")  # Added this because page is really unstable :(

elements = driver.find_elements_by_css_selector(".gridTitle > span > a")
links = [elem.get_attribute('href') for elem in elements]
print(links)

【讨论】:

  • 嗨,这需要我安装 Chrome 驱动程序吗?给我的错误是 WebDriverException: Message: 'Desktop\chromedriver.exe' 可执行文件需要在 PATH 中。请参阅sites.google.com/a/chromium.org/chromedriver/home
  • 抱歉,答案中的链接中断了。你只需要将 download ChromeDriver executable 放在与你的脚本相同的文件夹中。
  • 嗨 Arthur,我已经成功下载并运行了该程序,但我还有一个问题。对于某些类别,它有多个页面,但 url 保持不变,即武术类别 (onepa.gov.sg/cat/martial-arts)。这意味着我无法循环 url 中的页面,无论如何我可以加载 url 中的所有元素,这样我就可以收集所有想要的信息?否则,代码只会收集第一页的信息。
  • 我认为该网站不允许您在一页上加载所有 1k 元素。所以我建议你看看how to loop over multiple pages with selenium
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-10
相关资源
最近更新 更多