【问题标题】:BeautifulSoup How to get href links from pseudo-element/ClassBeautifulSoup 如何从伪元素/类中获取 href 链接
【发布时间】:2020-09-09 22:20:34
【问题描述】:

我正在尝试解析 https://www.tandfonline.com/toc/icbi20/current 以获取所有文章的标题。 HTML 分为 Volumes 和 Issues。每个卷都有一个对应于一个月的问题。因此,对于第 36 卷,将有 12 个问题。在当前卷(37)中有 4 个问题,我想解析每个问题并获取每个文章的名称。

要完成此操作并自动执行搜索,我需要获取每个问题的 href 链接。最初我选择了父母的dividid = 'tocList'

import requests
from bs4 import BeautifulSoup, SoupStrainer

chronobiology = requests.get("https://www.tandfonline.com/toc/icbi20/current")
chrono_coverpage = chronobiology.content

issues = SoupStrainer(id ='tocList')
issues_soup = BeautifulSoup(chrono_coverpage, 'html.parser', parse_only = issues)
for issue in issues_soup:
    print(issue)

这将返回一个 bs4 对象,仅包含来自卷 divhref 链接。更糟糕的是,这个div 应该包含卷div 和问题div

所以,我决定尝试减少我的搜索空间并使其更具体,并选择包含问题 href 链接的 div 链接 (class_='issues')

这一次木星会想一想,但不会返回任何东西。只是空白。没有。芝宝。 但是如果我问返回了什么类型的“无”,jupiter 会告知它是“String”???我只是不知道该怎么做。

所以,首先我有一个问题,为什么问题div 元素不响应解析? 当我尝试运行print(BeautifulSoup(chrono_coverpage, 'html.parser').prettify()) 时,同样的情况会发生,问题div 不会出现(当html 页面上的Inspect Element 立即出现在最终卷span 下方时):

所以我怀疑它一定是面向 javascript 的,而不是面向 HTML 的。或者class = 'open' 可能与此有关。

任何澄清将不胜感激。另外,如何通过 Javascripted 链接解析来获取它们?

【问题讨论】:

    标签: python selenium web-scraping beautifulsoup


    【解决方案1】:

    好的,虽然我需要填补一些理论上的空白,但我已经“解决了”这个问题:

    首先这个sn-p是解开答案的关键:

    可以看出,<div class = 'container'> 后面紧跟着一个 ::before 伪元素,而我感兴趣的链接包含在该伪元素下方的 div 中。最后一个 div 然后用 ::after 伪元素完成。

    首先我意识到我的问题是我需要选择一个伪元素。我发现使用BeutifulSoupsoup.select() 是不可能的,因为显然BeautifulSoup 使用Soup Sieve,它“旨在允许用户使用CSS 选择器定位XML/HTML 元素。它实现了许多伪类[...]。"

    该段的最后部分指出:

    "Soup Sieve 也不会匹配任何 仅在实时浏览器环境中相关的伪类但如果它们已经实现,它会优雅地处理它们;

    所以这让我想到我不知道“仅在实时浏览器环境中相关的伪类”是什么意思。但后来我对自己说,“但它也说如果它们被实现,BS4应该能够解析它们”。而且由于我可以使用Inspect 工具肯定看到包含我感兴趣的href 链接的div 元素,我认为我必须实现。

    这句话的第一部分让我想到:“但是我需要一个实时浏览器才能让它工作吗?”

    所以这把我带到了Selenium 的网络驱动程序:

    import requests
    from bs4 import BeautifulSoup, SoupStrainer
    from selenium import webdriver
    
    driver = webdriver.Chrome()
    url_chronobiology = driver.get("https://www.tandfonline.com/toc/icbi20/current")
    chronobiology_content = driver.page_source
    chronobiology_soup = BeautifulSoup(chronobiology_content)
    chronobiology_soup.select('#tocList > div > div > div.yearContent > div.issues > div > div')
    
    [Out]: []
    

    很明显,这个结果让我很伤心,因为我以为我已经明白发生了什么。但是后来我认为,如果我从先前打开的浏览器中“单击”其中一个问题,它将起作用(出于某种原因,老实说,我很确定绝望使我产生了这种想法)。

    嗯,惊喜惊喜。它起作用了:点击“问题 4”并重新运行 script 后,我得到了我想要的东西:

    未回答的问题?

    1 - 显然,这些伪元素在点击时只会“存在”,否则代码无法识别它们的存在。为什么?

    2 - 必须运行什么代码才能进行初始点击并激活这些伪元素,这样代码才能自动打开这些链接并解析我想要的信息? (文章标题)

    更新

    使用 Selenium 的 ActionChain 回答问题 2:

    import requests
    from bs4 import BeautifulSoup, SoupStrainer
    from selenium import webdriver
    from selenium.webdriver.common.action_chains import ActionChains
    
    driver = webdriver.Chrome()
    url_chronobiology = driver.get("https://www.tandfonline.com/toc/icbi20/current")
    chronobiology_content = driver.page_source
    chronobiology_soup = BeautifulSoup(chronobiology_content)
    action=ActionChains(driver)
    action.move_to_element(driver.find_element_by_xpath('//*[@id="tocList"]/div/div/div[3]/div[2]/div')).perform()
    
    chronobiology_soup.select('#tocList > div > div > div.yearContent > div.issues > div > div')
    
    [Out]: 
    [<div class="loi-issues-scroller">
     <a class="open" href="/toc/icbi20/37/4?nav=tocList">Issue<span>4</span></a>
     <a class="" href="/toc/icbi20/37/3?nav=tocList">Issue<span>3</span></a>
     <a class="" href="/toc/icbi20/37/2?nav=tocList">Issue<span>2</span></a>
     <a class="" href="/toc/icbi20/37/1?nav=tocList">Issue<span>1</span></a>
     </div>]
    

    唯一的缺点是必须留在页面上SeleniumActionChain.perform()才能真正点击元素,至少我已经自动化了这一步。

    如果有人能回答问题 1,那就太好了

    【讨论】:

      猜你喜欢
      • 2021-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      相关资源
      最近更新 更多