【问题标题】:Scraping using selenium使用硒刮擦
【发布时间】:2020-06-02 19:16:16
【问题描述】:

您好,我正在尝试抓取我最初使用 Bs4 的这个网站,这样可以获取某些元素。部门、名称等。但我无法使用它来获取财务数据。下面我复制了一些page_source,“-”在这种情况下应该是0.0663。我相信我正在尝试抓取 javascript,我环顾四周,但我所看到的解决方案都没有为我工作。我想知道是否有人可以帮我破解这个。

虽然如果有人可以发布一些工作代码,我将不胜感激,但如果您能指出正确的方向以及了解要在 html 中查找的内容,我也会非常感激,这向我展示了我需要做什么以及如何做得到它有点东西。

网址:https://www.tradingview.com/symbols/LSE-TSCO/

HTML:

<span class="tv-widget-fundamentals__label apply-overflow-tooltip">
    Return on Equity (TTM)
</span>
<span class="tv-widget-fundamentals__value apply-overflow-tooltip">
    —
</span>

Python 代码:

url = "https://www.tradingview.com/symbols/LSE-TSCO/"
options = webdriver.ChromeOptions()
options.add_argument('headless')
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get(url)
html = driver.page_source

【问题讨论】:

  • 很抱歉,我们没有足够的信息来帮助您。请发帖minimal reproducible example
  • 我已经对其进行了编辑,但除了代码无法正常工作之外,我不知道该怎么做,我目前所能做的就是刮掉没有显示我需要的数字的 page_source出现为“_”所以如果我刮什么都不会返回所以网站上的代码必须像后门或类似的东西,但我不知道如何访问它,因为我是新手

标签: python-3.x selenium selenium-webdriver web-scraping beautifulsoup


【解决方案1】:

获取权益值。诱导WebDriverWait() 并等待visibility_of_element_located() 及以下xpath。

driver.get(url)
print(WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.XPATH,"//span[contains(.,'Return on Equity (TTM)')]/following-sibling::span[1]"))).text)

您需要导入以下库。

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

【讨论】:

  • @JPWilson:这应该是你的答案。 'sleep' 提出的答案是一个非常脆弱的 XPath,如果站点所有者出于任何原因更改页面,很容易出错。
  • 感谢您的帮助,我已经实现了您的脚本,但无论出于何种原因,如果它无法获取数据点并给出“-”,它似乎不会等待 10 秒。因此,如果我执行脚本 5 次,我可以获得所有内容,或者我查看的前 3/4 项将是“-”,您建议我如何解决此问题?
  • 我在发布之前测试了代码,每次都给出正确的值。不知道为什么你得到“-”而不是值。你复制了我的整个代码并运行它吗?
  • 我添加了一个 time.sleep(2) 似乎可以解决它。我确实有一个问题是如何使它适用于抓取大量数据,例如这是一页,但如果我想对所有代码执行此操作,与使用 bs4 相比,硒需要很长时间,有没有办法加快速度或好办法吗?
  • @JPWilson :由于 javascripts 呈现的数据您需要 selenium 来获取 pagesouce,然后您可以使用 bs4.Bs4 仅适用于静态内容而不是动态内容。如果您发布一个符合预期的新问题输出然后我可以帮助您使用 selenium 和 bs4 来回答您的问题。
【解决方案2】:

您可以使用xpath获得股本回报

equity = driver.find_element_by_xpath('/html/body/div[2]/div[4]/div/div/div/div/div/div[2]/div[2]/div[2]/div/div[2]/div[1]/div/div/div[1]/div[3]/div[3]/span[2]').text
print(equity)

【讨论】:

  • 您好,谢谢,您能推荐一种方法而不是另一种方法吗?
  • Cheers mate 是 xpath 从字面上一直跟随标签吗?它只是经验带来的东西还是有快速的方法来解决它?最后你必须为此使用硒吗?或者你可以使用 requests 和 bs4 吗?
  • 如果您使用的是谷歌浏览器,您可以使用检查元素,然后右键单击并点击“复制完整 XPATH”,它会为您执行此操作,您可以使用请求和 bs4 执行此操作。不需要是硒
  • 投反对票。这是使用 xpath 的最糟糕的方式。对页面的任何更改并保证您的 xpath 都将被破坏。如果您使用 xPath,请使用相对路径,而不是像答案那样绝对。对于使用的选择器,我建议使用 id 而不是 css_selector,最后使用 xPath。
【解决方案3】:

这里的问题不在于元素是否存在,而是页面加载所需的时间。页面看起来很重,包含所有这些动态图表。甚至在页面完全加载之前,DOM 就开始创建并且默认值正在发生。

WebDriverWaitfind_element_* 在元素当前不存在但需要一定时间才能出现时有效。在您的上下文中,它从一开始就存在,添加它不会有太大作用。这也是您得到“-”的原因,因为该元素以其默认值存在。

要解决此问题或减少问题,您可以添加代码以等待文档 readyState 完成

可以使用这样的东西:

def wait_for_page_ready_state(driver):
    wait = WebDriverWait(driver, 20)

    def _ready_state_script(driver):
        return driver.execute_async_script(
                """
                var callback = arguments[arguments.length - 1]; 
                callback(document.readyState);
                """) == 'complete'
    wait.until(_ready_state_script)

wait_for_page_ready_state(driver)

那么既然你带来了 bs4,我会在这里使用它:

financials = {}
for el in BeautifulSoup(driver.page_source, "lxml").find_all('div', {"class": "tv-widget-fundamentals__row"}):
    try:
        key = re.sub('\s+', ' ', el.find('span', {"class": "tv-widget-fundamentals__label "
                                                       "apply-overflow-tooltip"}).text.strip())
        value = re.sub('\s+', ' ', el.find('span', {"class": "tv-widget-fundamentals__value"}).text.strip())


        financials[key] = value
    except AttributeError:
        pass

这将为您提供金融卡所需的所有价值。

你现在可以打印你需要的值了:

print(financials['Return on Equity (TTM)'])

输出:

'0.0663'

当然,您也可以使用 selenium 执行上述操作,但希望提供您开始使用的内容。

需要注意的是,这并不能保证总是返回正确的值。在我的情况下它可能并且确实如此,但是由于您知道默认值,您可以添加一个 while 循环,直到默认值更改。

[编辑] 在循环中运行我的代码后,我达到了默认值 1/5 次。解决它的一种方法是创建一个方法并循环直到达到阈值。在我的发现中,您将始终使用数字更新约 90% 的值。当它使用默认值失败时,所有其他值也位于“-”。一种方法是使用阈值(即 50% 并且仅在达到阈值后才返回值)。

    def get_financial_card_values(default_value='—', threshold=.5):
        financials = {}
        while True:
            for el in BeautifulSoup(driver.page_source, "lxml").find_all('div', {"class": "tv-widget-fundamentals__row"}):
                try:
                    key = re.sub('\s+', ' ', el.find('span', {"class": "tv-widget-fundamentals__label "
                                                                       "apply-overflow-tooltip"}).text.strip())
                    value = re.sub('\s+', ' ', el.find('span', {"class": "tv-widget-fundamentals__value"}).text.strip())

                    financials[key] = value
                except AttributeError:
                    pass
            number_of_updated_values = [value for value in financials.values() if value != default_value]
            if len(number_of_updated_values) / len(financials) > threshold:
                return financials

使用这种方法,我总能检索到您期望的值。请注意,如果所有值都不会改变(站点问题),您将永远处于循环中,您可能希望使用计时器而不是 while True。只是想指出这一点,但我认为这不会发生。

【讨论】:

  • 感谢您的详细回复,我看到的一家名为 Eddie Stobbart 的物流公司几乎没有任何数据会弄乱新生,因此我可能不得不使用 Yfinance,我已经有一个不错的刮刀,我想如果需要我也可以使用 api。
  • 这是一个如何解决值的示例,您可以使用必须始终更改或为数字的键。在您的情况下,您将使用 Return on Equity (TTM) 并确保这个会改变。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-06
  • 1970-01-01
  • 2022-01-12
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多