python - 使用 python selenium 读取、写入和控制动态实例化的 HTML web 表
问题描述
假设有一些特定的搜索者搜索一些商品,我用“泰迪”搜索。总结果数为 140,并显示在由<div>
每行和每列组成的小表格中(每个内容为行,内容为信息的列),并带有滚动条。这向我展示了一个很好的列表,最多可显示 5 个(每个内容的高度为 40px),如果我需要查看更多内容,我需要向下滚动此表。
如果我在第 45 到第 49 处看到商品(第 45 条内容位于当前视图的顶部),则 HTML 如下所示。
<div class="table-body" style="height:200px"> // This contains scrollbar
<div class="table-panel" style="height:5600px">
<div class="ag-row" style="height:40px row="42"> // This is each row of goods
<div class="name">Teddy</div> // This is each column of good
<div class="price">200</div>
<input class="amount">0</input> // Input text box for put amount of goods to buy
</div>
<div class="ag-row" style="height:40px row="43">
<div class="name">Brown Bess</div>
<div class="price">230</div>
<input class="amount">0</input>
</div>
<div class="ag-row" style="height:40px row="44"> // <-- This is what I'am seeing at the top. 0 based row attribute
<div class="name">Blue</div>
<div class="price">280</div>
<input class="amount">0</input>
</div>
<div class="ag-row" style="height:40px row="45">
<div class="name">Scientist</div>
<div class="price">400</div>
<input class="amount">0</input>
</div>
<div class="ag-row" style="height:40px row="46">
<div class="name">Mouse</div>
<div class="price">120</div>
<input class="amount">0</input>
</div>
<div class="ag-row" style="height:40px row="47">
<div class="name">Hangover</div>
<div class="price">150</div>
<input class="amount">0</input>
</div>
<div class="ag-row" style="height:40px row="48"> // <-- This is what I'am seeing last.
<div class="name">Building</div>
<div class="price">420</div>
<input class="amount">0</input>
</div>
<div class="ag-row" style="height:40px row="50">
<div class="name">Park</div>
<div class="price">60</div>
<input class="amount">0</input>
</div>
<div class="ag-row" style="height:40px row="51">
<div class="name">Coffee</div>
<div class="price">160</div>
<input class="amount">0</input>
</div>
<div class="ag-row" style="height:40px row="49">
<div class="name">Juice</div>
<div class="price">100</div>
<input class="amount">0</input>
</div>
</div>
</div>
这也是我的虚构代码,实际代码由于其样式、属性和脚本而复杂得多。我认为问我的主题就足够了。
我检查了这个网页的行为。它只会使它成为我所看到的附近的 html。当我看到接近第 100 个内容时,它会在第 92 到 108 个之间创建 html——实例化的数量是非常随机的。当我向下或向上滚动时,它会删除远离当前位置的内容并为当前屏幕创建新内容。
我需要解析这些数据,并且需要在 python 中创建一些类似列表的数据结构。因为它根据屏幕实例化部分数据(准确地说,它似乎使用滚动条来检查我看到的位置)我试图控制滚动条并裁剪 html 中的所有数据并删除重复项。代码如下
from selenium import webdriver
..blah..
def iterateOptionTable(driver):
el_viewport = driver.find_element_by_class_name('table-body')
driver.execute_script('document.getElementsByClassName("{}")[0].scrollTop = 0;'.format('table-body'))
max_height = int(driver.execute_script('return document.getElementsByClassName("{}")[0].scrollHeight;'.format('table-body')))
scrolling_amnt = int(40 * 5) # Each row height is 40
cur_scroll = 0
table = defaultdict(int) # Don't put into list which is already pushed
ret = []
while cur_scroll < max_height:
el_products = el_viewport.find_elements_by_xpath('./div/*')
for el_p in el_products:
rownum = int(el_p.get_attribute("row"))
if rownum not in table:
table[rownum] = True
ret.append(el_p)
yield ret # List of WebElement of good
ret.clear()
cur_scroll += scrolling_amnt
driver.execute_script('document.getElementsByClassName("{}")[0].scrollTop = {};'.format('table-body', cur_scroll))
def parseElementToData(elems):
ret = []
for el in elems:
single_data = DO_EXTRACT_DATA_FROM_EL()
ret.append(single_data)
def parseTable(driver):
ret = []
for elems in iterateOptionTable(driver):
data += parseElementToData(elems)
return ret
该页面还有其他几个作业,yield
由于网页层次结构,它是使用编程的。
当我一一执行时,它在调试器中运行良好。但在实际运行时,它甚至不会向下滚动它的表格。更不用说我认为它效率低下。还通过从 selenium 执行脚本尝试了相同版本的 Javascript。
是否有更复杂的方法,或者我可以得到为什么这些在正常情况下不起作用的答案。我对网络爬行和硒很陌生。请帮忙 :)
解决方案
您可以看到元素的事实并不意味着它们已经在 HTML 中,它们必须具有 display: hidden 直到您滚动到它们。
现在我在这里假设,因为您没有提供相关网页的链接,我将尝试用您提供的代码进行解释。
我的建议是将表 1 中的所有行按 1 返回:
i = 0
row_list = []
while True:
try:
name = driver.find_element_by_xpath(x_path_to_the_row[i]/div).get_attribute('innerHTML'
price = driver.find_element_by_xpath(x_path_to_the_row[i]/div[2]).get_attribute('innerHTML')
row_list.append((name, price))
except NoSuchElementException:
break
i += 1
基本上循环直到表的元素不存在,获取该行的列并构造一个包含两个元素的元组。
注意:除非 HTML 位于 Shadow DOM 组件中,否则应该不会有问题。
推荐阅读
- kotlin - 使用 RxJava 在一段时间后发出项目
- magento - 在 Magento 2 中使用 REST API 为现有货件添加新的跟踪号
- unit-testing - 将测试从一个 HTTP 客户端重用到另一个
- ios - 快速过滤多维数组
- javascript - 尝试在 wordpress javascript 中提取 acf 字段时出现错误
- python - opencv:使用蒙版的黑色边框
- php - (php) 条件运算符有什么问题?有一个函数可以确定关联数组是否有任何键
- flake8 - 如何安装 Flake8-SQL 插件并运行其规则
- sql - 使用 T-SQL 从列中提取第一个争论
- android - 为什么只有某些应用程序在使用 adb 卸载应用程序的命令中出现错误?