Python BeautifulSoup如何从伪元素/类获取href链接

Python BeautifulSoup如何从伪元素/类获取href链接,python,selenium,web-scraping,beautifulsoup,Python,Selenium,Web Scraping,Beautifulsoup,我试图解析所有文章的标题。HTML分为卷和期。每卷都有一期,对应于一个月。因此,第36卷将有12期。在当前的卷(37)中有4个问题,我想分析每个问题并获得每篇文章的名称 为了实现这一点并自动搜索,我需要获取每个问题的href链接。最初,我选择了父级的divid:id='tocList' import requests from bs4 import BeautifulSoup, SoupStrainer chronobiology = requests.get("https://www.ta

我试图解析所有文章的标题。
HTML
分为卷和期。每卷都有一期,对应于一个月。因此,第36卷将有12期。在当前的卷(37)中有4个问题,我想分析每个问题并获得每篇文章的名称

为了实现这一点并自动搜索,我需要获取每个问题的
href
链接。最初,我选择了父级的
div
id
id='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对象,但只返回卷
div
中的
href
链接。更糟糕的是,这个
div
应该包括卷
div
和发行
div

因此,我决定尽量减少我的搜索空间,使其更加具体,并选择了包含问题
href
链接的
div
class='issues'

这一次木星会想一想,但不会返回任何东西。一片空白。没有什么。齐波但是如果我问返回了什么类型的“nothing”,jupiter会通知它是一个“
字符串”
”???我只是不知道该怎么办。

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

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

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

好的,我已经解决了这个问题,尽管我需要填补一些理论空白:

首先,这段代码是解决问题的关键:

可以看到,
后面紧跟着一个
::before
伪元素,我感兴趣的链接包含在这个伪元素下面的
div中。最后一个
div
::after
伪元素完成

首先我意识到我的问题是我需要选择一个伪元素。我发现这对于
BeutifulSoup
soup.select()
是不可能的,因为显然
BeutifulSoup
使用了
soup-siever
,它“旨在允许用户使用CSS选择器以XML/HTML元素为目标。它实现了许多伪类[…]”

该段最后一部分指出:

“对于仅在实时浏览器环境中相关的伪类,汤筛也不会匹配任何内容,但如果它们已经实现,它将优雅地处理它们。”

所以这让我觉得我不知道“只有在实时浏览器环境中才相关的伪类”是什么意思。但后来我对自己说,“但它也说,如果它们已经实现,BS4应该能够解析它们”。由于我可以使用
Inspect
工具明确地看到
div
元素,其中包含我感兴趣的
href
链接,因此我认为我必须实现

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

这让我想到了Selenium的web驱动程序:

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')
很明显,这个结果让我很伤心,因为我认为我已经明白发生了什么。但后来我想,如果我从之前打开的浏览器中“点击”了其中一个问题,它会起作用(出于某种原因,老实说,我很确定绝望让我产生了这种想法)

嗯,惊喜惊喜。它成功了:在点击“问题4”并重新运行
脚本后,我得到了我想要的:

未回答的问题?

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]:
[
]
唯一的缺点是人们必须停留在页面上查看
Selenium
ActionChain。perform()
实际上可以单击元素,但是至少我已经自动化了这一步

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

好的,所以我已经解决了这个问题,尽管我需要填补一些理论空白:

首先,这段代码是解决问题的关键:

可以看到,
后面紧跟着一个
::before
伪元素,我感兴趣的链接包含在这个伪元素下面的
div中。最后一个
div
::after
伪元素完成

首先我意识到我的问题是我需要选择一个伪元素。我发现这对于
BeutifulSoup
soup.select()
是不可能的,因为显然
BeutifulSoup
使用了
soup-siever
,它“旨在允许用户使用CSS选择器以XML/HTML元素为目标。它实现了许多伪类[…]”

该段最后一部分指出:

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>]