我目前正在网上抓取我的大学网页以下载单元内容。我已经找到了如何收集每个单元的名称/链接,现在正试图找到如何整理单元中每个单独模块的名称/连接。
模块页面上HTML的大致描述。
<ul id="content_listContainer" class="contentList">
<li id="" class="clearfix liItem read">
<img></img>
<div class="item clearfix">
<h3>
<a href="Link To Module">
<span>Name of Module</span>
</a>
</h3>
</div>
</li>
<li id="" class="clearfix liItem read">
<img></img>
<div class="item clearfix">
<h3>
<a href="Link To Module">
<span>Name of Module</span>
</a>
</h3>
</div>
</li>
</ul>
因此,我试图获取li/div/h3中<a>
标记的href属性内的链接,以及<a>
标记内span内模块的名称。以下是相关的代码片段。
modules = []
driver.get(unit_url)
module_ul = driver.find_element_by_xpath("//ul[@id='content_listContainer']") #Grab the ul list
li_items = module_ul.find_elements_by_xpath("//li[@class='clearfix liItem read']") #Grab each li item
for item in li_items[1:]: #Skips first li tag as that is the Overview, not a module
module_url = item.find_element_by_xpath("//div[@class='item clearfix']/h3/a").get_attribute('href')
#These are not moving on from the first module for some reason...
module_name = item.find_element_by_xpath("//div[@class='item clearfix']/h3/a/span").text
module = {
"name": module_name,
"url": module_url
}
modules.append(module)
问题:
编辑
不幸的是,我尝试过@sushii和@QHarr解决方案,但没有成功。我应该指出,在for循环中获取module_name和module_url的行在每个loop中都返回相同的第一个模块数据。我用另一个单元测试了它,其中第一对<li>
标签是非模块的(介绍(,应该返回,但它仍然只返回相同的模块1。
/edit
编辑2
这是我试图抓取的html的链接。这不是整个页面,因为那样会太大。
<html><body><div></div><div></div><div></div><div>
这是链接中的DIV</div><div></div><div></div></body></html>
我已经验证了li_items肯定包含我需要的<li>
标记,所以其他HTML应该不重要(我认为(。
如果向下滚动约四分之一,则我需要的<li>
标记为粗体,并且我需要抓取的信息为下划线。
/编辑2
在for循环中获取module_name和module_url的行只获取第一个模块的信息。
我已经通过调试验证了li_items确实包含了所有的li项,而不仅仅是获取第一个。我是Selenium的新手,所以我的想法是我提供的xpath有问题,但它应该只抓取项可迭代对象中的标记。所以我很困惑为什么它一直在抓取第一个李的信息。
应答编辑
使用@Sariq Shaikh的答案,我解决了这个问题。最初,他使用元素索引[]来迭代<li>
标记的技术不起作用,但在更改用于module_url和module_name的XPATH以包括<ul>
标记,然后使用<li>
标记的索引后,解决了我的问题。
然而,我仍然不明白为什么最初的方法不起作用。这是修改后的代码。
module_ul = driver.find_element_by_xpath("//ul[@id='content_listContainer']")
ctr = 1
for _ in module_ul.find_elements_by_tag_name('li'):
try:
module_url = driver.find_element_by_xpath('//ul[@id="content_listContainer"]/li[' + str(ctr) + ']/div/h3/a').get_attribute('href') #These are not moving on from the first module for some reason...
module_name = driver.find_element_by_xpath('//ul[@id="content_listContainer"]/li[' + str(ctr) + ']/div/h3/a/span').text
except SelException.NoSuchElementException:
print("NoSuchElementExceptionn")
ctr += 1
continue
要迭代地获取所有列表项,可以使用xpath和index,如下所示。
(//div[@class='item clearfix'])[1] #first li item index starts from 1 not 0
(//div[@class='item clearfix'])[2] #second li item
(//div[@class='item clearfix'])[3] #third li item
(//div[@class='item clearfix'])[4] #fourth li item
在使用索引获取每个li项之后,您可以根据它们在xpath中的存在来访问其子元素,如下所示。
(//div[@class='item clearfix'])[1]/h3/a #first li's h3/a tag
考虑到这一点,您可以更新您的代码,如下所示,使用一个简单的计数器来获取基于索引的列表元素。
modules = []
module_ul = driver.find_element_by_xpath("//ul[@id='content_listContainer']") #Grab the ul list
li_items = module_ul.find_elements_by_xpath("//li[@class='clearfix liItem read']") #Grab each li item
counter = 1 #use counter to iterate over all the li items based on index
for item in li_items:
#append counter values as index for list items in xpath
module_url = item.find_element_by_xpath("(//div[@class='item clearfix'])["+str(counter)+"]/h3/a").get_attribute('href')
module_name = item.find_element_by_xpath("(//div[@class='item clearfix'])["+str(counter)+"]/h3/a/span").text
module = {
"name": module_name,
"url": module_url
}
modules.append(module)
counter= counter + 1
#remove the first item from the list as its not required
modules.pop(0)
print(modules)
使用BeautifulSoup
实际上非常简单。以下是如何使用BeautifulSoup
:
from bs4 import BeautifulSoup
html = """
<ul id="content_listContainer" class="contentList">
<li id="" class="clearfix liItem read">
<img></img>
<div class="item clearfix">
<h3>
<a href="Link To Module">
<span>Name of Module</span>
</a>
</h3>
</div>
</li>
<li id="" class="clearfix liItem read">
<img></img>
<div class="item clearfix">
<h3>
<a href="Link To Module">
<span>Name of Module</span>
</a>
</h3>
</div>
</li>
</ul>
"""
soup = BeautifulSoup(html,'html.parser')
lis = soup.find_all('li',class_ = 'clearfix liItem read')
for li in lis:
print(li.div.h3.a['href'])
输出:
Link To Module
Link To Module
希望这能有所帮助!
编辑:
由于ur网站是使用javascript
动态加载的,因此u shd首先在selenium中打开url,获取网站的html代码并关闭浏览器。以下是你的操作方法:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get(url)
html = driver.page_source
然后U可以使用BeautifulSoup
解析这个html。希望这能有所帮助!
您应该能够使用css选择器并避免循环。
import pandas as pd
results = pd.DataFrame(zip([i.text for i in driver.find_elements_by_css_selector('#content_listContainer span')]
, [i.get_attribute('href') for i in driver.find_elements_by_css_selector.('#content_listContainer a')])
, columns = ['Name', 'Link'])
print(results)
我刚刚遇到了一个非常类似的问题,虽然我不确定为什么,但我想我已经找到了一个解决方案:
如果更换
module_url = item.find_element_by_xpath("//div[@class='item clearfix']/h3/a").get_attribute('href')
带有
module_url = item.find_element_by_xpath("./div[@class='item clearfix']/h3/a").get_attribute('href')
在中,在xpath开始时用./
替换//
(并在module_name
xpath中进行相同的替换(,那么我认为它应该可以工作。我在你提供的html上尝试过,它似乎有效。再说一次,我真的不确定它为什么有效,我试过查看XPath文档,但老实说,这对我来说都是希腊语。