如何遍历隐藏的div和剪贴文本?

时间:2019-07-06 04:37:58

标签: python selenium web-scraping

我正在尝试使用可扩展的div刮取一个网站,该div隐藏了其中的文本,而我试图对其进行刮擦。我只能在第一个可扩展div中抓取文本。但是,我可以单击所有div。如何从所有div抓取文字?

关闭的HTML:

<li class="views-row views-row-1 pub1 default-on clk" tabindex="150">  
          <div class="teaser Speeches col-xs-12 col-sm-12 col-md-12 col-lg-12 crop2" data-nid="50849" data-tid="6971" aria-hidden="false">
  <div class="thumb" style="padding-top: 0px; padding-bottom: 0px;">
  <img class="img-responsive" src="/sites/pm/files/styles/news_listing_square/public/default_news/20180501_default_news2.jpg?itok=a1pfZTOA" alt="" title=""></div>
  <div class="news-teaser">
    <div class="title">TITLE</div>
    <div class="body">TEASER TEXT</div>
    <div class="category">Speeches<br>PLACE <span class="date-display-single" property="dc:date" datatype="xsd:dateTime" content="2019-06-10T18:15:00-04:00">June 10, 2019</span></div>
  </div>
</div>
<div class="sticky0"></div>
<div class="full-article" aria-hidden="true"></div>  
</li>
<li class="views-row views-row-2 pub1 default-on clk" tabindex="150"> </li>
<li class="views-row views-row-3 pub1 default-on clk" tabindex="150"> </li>

点击该项目后,可以看到完整的语音:

<li class="views-row views-row-1 pub1 default-on clk active" tabindex="150">     
          <div class="news-article-body-fields">    
          <h1 class="field-content">TITLE</h1>    

          <div class="image col-xs-12 col-sm-12 col-md-12 col-lg-12 news-image-caption">
<span class="caption"></span>
</div>    
          <span class="field-content Speeches-news-article-date"><div class="inline-date">
  PLACE <span class="date-display-single" property="dc:date" datatype="xsd:dateTime" content="2019-06-10T18:15:00-04:00">June 10, 2019</span>
</div></span>    
  <div class="views-field views-field-body">        <p><span lang="EN-CA" xml:lang="EN-CA">CHECK AGAINST DELIVERY</span></p><p><span lang="EN-CA" xml:lang="EN-CA">Good morning, everyone. </span></p><p><span lang="EN-CA" xml:lang="EN-CA">Before we get into things, I want to take a second to thank ____ – for his introduction, yes, but more importantly, for his leadership. </p> SPEECHES CONTINUE IN <P> TAGS. 

这是我的Python脚本:

# Libraries
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import requests
import time

# Opening up connection and grabbing HTML file via Chrome
url = 'https://pm.gc.ca/eng/news/speeches'
browser = webdriver.Chrome()
browser.get(url)

# Delaying scrapper to prevent scrapper from closing too soon
browser.implicitly_wait(2)

# Creating loop to open up all divs with same class name
article_list = browser.find_elements_by_css_selector(".views-row.pub1.default-on.clk")

# All titles for expanded divs printed. Works!
for article in article_list:
    print(article.text)


# Only works for first article in list
for article in article_list:
    article.click()

    time.sleep(3)

    # Getting title
    title = browser.find_element_by_xpath("//h1[@class = 'field-content']")
    print(title.text)   

    # Getting date
    date = browser.find_element_by_class_name("date-display-single")
    print(date.text)

    # Getting place
    place = browser.find_element_by_xpath("//div[@class = 'inline-date']")
    print(place.text)

    # Getting speech
    speech_div = browser.find_elements_by_xpath("//span[@lang = 'EN-CA']")

    for p in speech_div:
        print(p.text)

目前,我可以删除第一篇文章的全文。然后,驱动程序单击到下一个可扩展div中的第二个语音,输出一整段空白,并以与第二个语音相同的方式继续播放下几个语音(整个空白空间)。

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:1)

您需要将搜索范围定为当前div,而不是整个文档。在当前元素(find*而不是article)上调用browser

title = article.find_element_by_xpath("//h1[@class = 'field-content']")
speech_div = article.find_elements_by_xpath("//span[@lang = 'EN-CA']")

答案 1 :(得分:1)

语音详细信息是使用AJAX请求加载的。这意味着您甚至不必为此使用硒,仅requests就足够了,这可以使速度大大提高:

import requests
from bs4 import BeautifulSoup

headers = {
    'User-Agent':  'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0'
}


def make_soup(url: str) -> BeautifulSoup:
    res = requests.get(url, headers=headers)
    res.raise_for_status()
    return BeautifulSoup(res.text, 'html.parser')


def fetch_speech_details(speech_id: str) -> str:
    url = f'https://pm.gc.ca/eng/views/ajax?view_name=news_article&view_display_id=block&view_args={speech_id}'
    res = requests.get(url, headers=headers)
    res.raise_for_status()
    data = res.json()
    html = data[1]['data']
    soup = BeautifulSoup(html, 'html.parser')
    body = soup.select_one('.views-field-body')
    return str(body)


def scrape_speeches(soup: BeautifulSoup) -> dict:
    speeches = []
    for teaser in soup.select('.teaser'):
        title = teaser.select_one('.title').text.strip()
        speech_id = teaser['data-nid']
        speech_html = fetch_speech_details(speech_id)
        s = {
            'title': title,
            'details': speech_html
        }
        speeches.append(s)


if __name__ == "__main__":
    url = 'https://pm.gc.ca/eng/news/speeches'
    soup = make_soup(url)
    speeches = scrape_speeches(soup)
    from pprint import pprint
    pprint(speeches)

输出:

[
    {'title': 'PM remarks for Lunar Gateway', 'details': '<div class="views-field views-field-body"> <p>CHECK AGAINST DELIVERY</p><p>Hello everyone!</p><p>I’m delighted to be here at the Canadian Space Agency to share some great news with Canadians.</p><p>I’d like to start by thanking the President of the Agency, Sylvain Laporte ... },
    {...},
    ....
]