- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试开发一个可持续的网络抓取脚本,以从网站获取所有产品的列表。产品类别链接位于网页的下拉(或可扩展)元素中。在提取 html 并使用 Beautiful Soup 将其转换为文本之前,我使用 PyQt5 来模拟客户端。
例如,如果您在浏览器上访问网站,则必须单击页面左上角附近的按钮才能打开从屏幕左侧弹出的类别列表(我将将其称为“边栏”)。在每个类别中,单击时都会有一个更具体类别的列表,每个类别都有一个我试图用我的代码获取的链接(我将这些称为“子类别”)。
即使侧栏被隐藏,初始类别列表元素也会出现在我的 Beautiful Soup 中,但子类别元素保持隐藏状态,除非子类别标题展开(因此,它们不会出现在我的汤中).我已通过手动检查 Chrome 浏览器中的元素来确认这一点。这是网页 HTML 的片段,其中包含我自己的评论以帮助解释:
<div aria-label="Fruits & Vegetables" data-automation-id="taxonomy-toggle-Fruits & Vegetables">
<button aria-disabled="false" aria-expanded="false" class="NavSection__sectionBtn___1_cAs" data-
automation-id="nav-section-toggle" tabindex="-1"> #Initial category that contains sub-categories
</button>
<div>
</div> #Contains the links I need, but doesn't populate HTML text unless sub-category element is expanded
</div>
下面是子类别元素展开后的样子:
<div aria-label="Fruits & Vegetables" data-automation-id="taxonomy-toggle-Fruits & Vegetables">
<button aria-disabled="true" aria-expanded="true" class="NavSection__sectionBtn___1_cAs" data-
automation-id="nav-section-toggle" tabindex="-1"> #Initial category that contains sub-categories
</button>
<div>
<ul class>
<li class = "NavSection__sectionLink__rbr40> </li>
<li class = "NavSection__sectionLink__rbr40> </li> #can open each li element up to acquire href link
<li class = "NavSection__sectionLink__rbr40> </li>
</ul>
</div>
</div>
这是我的代码:
import bs4 as bs
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEnginePage
#act as a client via Qt5 to acquire javascript elements from webpage
class Page(QWebEnginePage):
def __init__(self, url):
self.app = QApplication(sys.argv)
QWebEnginePage.__init__(self)
self.html = ''
self.loadFinished.connect(self._on_load_finished)
self.load(QUrl(url))
self.app.exec_()
def _on_load_finished(self):
self.html = self.toHtml(self.callable)
print("Load Finished")
def callable(self, html_str):
self.html = html_str
self.app.quit()
page = Page("https://grocery.walmart.com")
soup = bs.BeautifulSoup(page.html, 'lxml')
print(soup.prettify())
我知道如果aria-expanded
和 aria-disabled
<button>
的属性子类别 <li>
元素从“False”更改为“True”元素将出现在 HTML 中。我通过 Chrome 浏览器中的手动检查确认了这一点。
我的问题是是否有可能获得 href
来自 <li>
元素?我的假设是我必须编辑 HTML 才能更改 aria
在初始解析后将属性从“False”更改为“True”,然后使用这些更改重新解析 HTML。如果没有,除了 Selenium 之外,还有其他方法可以从网页中获取这些元素吗?我正在尝试使用更精简的方法(不打开浏览器窗口等)。
我可以提供实际的网站 URL 和网页截图来帮助澄清,但不确定这是否被认为是好的做法或 Stack Overflow 是否允许(我是新来的!)。
有关我尝试使用的方法的更多背景信息,请参阅以下内容:
最佳答案
如果您从页面下载 HTML,您会发现几乎整个页面都是使用 javascript 创建的,因此 Beautiful Soup 不是正确的工具,因为它仅用于分析 HTML。在这种情况下,解决方案是使用 runJavaScript()
通过 javascript 实现逻辑。 QWebEnginePage
的方法:
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
class WalmartGroceryPage(QtWebEngineWidgets.QWebEnginePage):
def __init__(self, parent=None):
super().__init__(parent)
self._results = None
self.loadFinished.connect(self._on_load_finished)
self.setUrl(QtCore.QUrl("https://grocery.walmart.com"))
@QtCore.pyqtSlot(bool)
def _on_load_finished(self, ok):
if ok:
self.runJavaScript(
"""
function scraper_script(){
var results = []
self.document.getElementById("mobileNavigationBtn").click();
var elements = document.getElementsByClassName("NavSection__sectionBtn___1_cAs");
for (const element of elements) {
element.click();
var items = [];
var sub_elements = document.getElementsByClassName("MobileNavigation__navLink___2-m6_");
for (const e of sub_elements) {
var d = {"name": e.innerText, "url": e.href};
items.push(d);
}
var data = {"name": element.innerText, "items": items};
results.push(data);
}
return results;
}
scraper_script();
""",
self.results_callback,
)
def results_callback(self, value):
self._results = value
QtCore.QCoreApplication.quit()
@property
def results(self):
return self._results
if __name__ == "__main__":
import sys
import json
# sys.argv.append("--remote-debugging-port=8000")
app = QtWidgets.QApplication(sys.argv)
page = WalmartGroceryPage()
ret = app.exec_()
results = page.results
print(json.dumps(results, indent=4))
输出:
[
{
"items": [
{
"name": "Fall Flavors Shop",
"url": "https://grocery.walmart.com/cp/Flavors%20of%20Fall/9576778812"
},
{
"name": "Baking Center",
"url": "https://grocery.walmart.com/browse?shelfId=3433056320"
},
{
"name": "Peak Season Produce",
"url": "https://grocery.walmart.com/browse?shelfId=4881154845"
},
# ...
关于python - PyQt5 QWebEnginePage - 可以编辑 HTML 以打开下拉列表吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58313185/
我们正在尝试将一些应用程序从 Qt 4 移植到 Qt 5.4。 Qt 5.4 有一个新的网络引擎。我们曾经把QWebView和QWebPage的背景做成透明的: view = new QWebView
我有这部分工作,但我面临几个困难: 1) 看来 QWebEnginePage 需要一个 QWebEngineView。 (请参阅此处的 setView() 方法: https://code.woboq
我使用QWebEnginePage.printToPdf方法来打印Qt 5.7中QWebEnginePage渲染的网页。但该方法仅呈现网络的一部分。 代码如下: webEngineView->page
在 Qt 的 (现已弃用) QWebPage 类中,有一个信号 contentsChanged() 每当网页的 html 内容被用户编辑页面或以编程方式更改的页面更改时调用。在较新的 QtWebEng
我在将 QWebEnginePage 连接到 fullScreenRequested 时遇到问题,我正在尝试以下方式,但它给出了错误 main.cpp:58: error: expected prim
我正在使用 QT WebEngine 框架来显示网页。我在页面加载时将 JavaScript 注入(inject)到页面中,并希望允许 JavaScript 能够访问 QT 对象。显然,要做到这一点,
我有一个使用 QWebChannel 启动 Webview 的 Qt 应用程序。 在这些 View 中,我让 JavaScript 执行一些操作,以便根据屏幕大小定位窗口/调整窗口大小。 screen
我有一个 QWebEnginePage 实例,它加载了一些 url(例如 https://www.google.com) 我希望此页面显示在两个 QWebEngineView 中,但看起来 Qt 不允
我正在尝试从 QWebEnginePage 对象中获取 html 代码。根据 Qt 引用,QWebEnginePage 对象的 'toHtml' 是异步方法,如下所示。 Asynchronous me
我正在尝试开发一个可持续的网络抓取脚本,以从网站获取所有产品的列表。产品类别链接位于网页的下拉(或可扩展)元素中。在提取 html 并使用 Beautiful Soup 将其转换为文本之前,我使用 P
本来想解决this problem , 但正如我测试过 QWebEnginePage::runJavaScript() 的行为一样,我发现我什至无法使用带有以下代码的 QWebEnginePage::
我需要从 QWebEnginePage 中检索一些 html。我在文档中找到了方法 toHtml但它总是返回一个空字符串。我试过 toPlainText 它有效,但这不是我需要的。 MyClass::
我在 PyQt5 代码中遇到错误。谁能帮我。 import sys from PyQt5.QtWidgets import QApplication from PyQt5.QtCore import
我正在尝试使用 print() 从 QWebEngineView 打印 html 文档方法和 QPrinter此方法所需的实例。 我遇到的问题是,在生成的 PDF 中,我无法选择任何可用的文本。 PD
我是一名优秀的程序员,十分优秀!