使用Python抓取网页上动态元素的第二页

时间:2020-11-03 21:01:00

标签: python selenium web-scraping

我为一个小组工作,该小组希望在Tx中提取端口状态的自动报告。为此,我正在尝试抓取海岸警卫队Homeport网站(我不太熟悉)。我设法使用Selenium通过带有端口的页面表的xpath提取所有信息,但是脚本的“表2”上有一个端口(维多利亚),脚本无法看到。如果我在页面之间切换,则xpath不会更改,因此我不确定如何找到它。任何帮助将不胜感激!

编辑:该页面使用Javascript元素。

https://homeport.uscg.mil/port-directory/corpus-christi

    url = 'https://homeport.uscg.mil/port-directory/corpus-christi'
    xpath= "/html/body/form/div[12]/div[2]/div[2]/div[2]/div[3]/div[1]/div[4]/div/div/div/div/div/div[1]/div/div[2]/div[1]/div/div/div[2]/div/div[2]/div/table"
    portsList = ['CORPUS CHRISTI','ORANGE','BEAUMONT','VICTORIA','CALHOUN','HARLINGEN','PALACIOS','PORT ISABEL','PORT LAVACA','PORT MANSFIELD']
                        
    df = pd.DataFrame(index=portsList, columns=['status','comments','dateupdated'])
    driver = webdriver.Chrome(executable_path = r"C:\Users\M3ECHJJJ\Documents\chromedriver.exe")
    urlpage = url+page
    driver.get(urlpage)
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);var lenOfPage=document.body.scrollHeight;return lenOfPage;")
    time.sleep(15)
    results = driver.find_elements_by_xpath(xpath)
    ports_split = results[0].text.split('\n')
    i = 0
    for port in ports_split:
         if port.upper() in portsList:
                print(port)
                df.xs(port.upper())['status'],df.xs(port.upper())['comments'],df.xs(port.upper())['dateupdated'] = parsePara(ports_split[i+1])
         i = i+1
    driver.quit()

1 个答案:

答案 0 :(得分:0)

首先,要非常小心地编写与政府网站(或与此有关的任何网站)相抵触的自动化程序,并确保您被允许这样做。您可能还会发现,许多网站都以结构化格式(例如通过API或数据下载)提供您正在寻找的信息。

尽管selenium为您提供了一个使浏览器实现自动化的出色工具,但其定位元素和解析HTML的功能可能还有很多不足之处。在这种情况下,我可能会使用BeautifulSoup作为与浏览器自动化一起使用的补充工具。

BeautifulSoup将支持与硒相同的所有定位器,但还提供其他功能,包括定义自己的元素定位标准的功能。

例如,您可以定义一个函数以使用非常特定的规则来定位元素(标签)。该函数应返回True以查找符合您兴趣的标签。

from bs4 import BeautifulSoup

def important_table(tag):
    """Given a particular tag, return True if it's what you're looking for"""
    return bool(
            # match <table> elements
            tag.name == 'table' and  
            # check for expected text
            any(port_name in tag.text for port_name in portsList) and 
            # check element attributes
            "classname" in tag.get('class', []) and
            # has at least 3 rows
            len(tag.findall('tr')) > 3  
            # and so on
             )

这只是一个示例,但是您可以根据需要编写此函数。

然后您可以这样应用

...
    driver.get(urlpage)
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);var lenOfPage=document.body.scrollHeight;return lenOfPage;")
    time.sleep(15)
    html = driver.page_source  # get the DOM content as a string
    soup = BeautifulSoup(html)
    table = soup.find(important_table)
    for row in table.findall('tr'):
        print(row.text)