#python #iframe #web-scraping #beautifulsoup
#python #iframe #очистка веб-страниц #beautifulsoup
Вопрос:
Я пытаюсь очистить некоторые данные с веб-сайта, используя BeautifulSoup. Я могу выбрать тег td, но он не содержит всех дочерних тегов, которые я ожидал бы. Моя цель — выполнить итерацию по тегу td с идентификатором =»highlight_today» и получить все сегодняшние события. URL, который я пытаюсь очистить, являетсяhttp://b-us.econoday.com/byweek.asp?containerId=eco-iframe-container . Это iframe на другой странице,http://www.bloomberg.com/markets/economic-calendar . Я думаю, что другой iframe может быть причиной того, что мой цикл for не работает, и я не извлекаю все теги, которые я ожидал бы в этом td. Мой опыт работы с html очень ограничен, поэтому я не уверен. Мой код выглядит следующим образом:
import re
import requests
from bs4 import BeautifulSoup
import time
url_to_scrape = 'http://b-us.econoday.com/byweek.asp?containerId=eco-iframe-container'
r = requests.get(url_to_scrape)
html = r.content
soup = BeautifulSoup(html, "html.parser")
for events in soup.find('td', {'id': "highlight_today"}):
print events.text
Я ожидаю получить все теги, содержащиеся в td, но в конечном итоге он останавливается на этом элементе в html-коде и не переходит к следующему div в td:
<span class="econoarticles"><a href="byshoweventfull.asp?fid=476382amp;amp;cust=b-usamp;amp;year=2016amp;amp;lid=0amp;amp;containerId=eco-iframe-containeramp;amp;prev=/byweek.asp#top">Daniel Tarullo Speaks<br></a></span>
Возможно, есть лучший способ выполнить это, чем мой текущий код. Я все еще довольно дилетант в этом, поэтому открыт для любых предложений о том, как достичь моей цели.
Ответ №1:
soup.find()
возвращает один тег. Возможно, вы имели в виду использовать find_all()
?
Кроме того, почему вы ожидаете найти более одного элемента с заданным идентификатором? Идентификаторы HTML (должны быть) уникальными для всего документа.
Ответ №2:
Попробуйте этот код. Используйте веб-драйвер Selenium.
from selenium import webdriver
import time
import datetime
import csv
import re
from datetime import timedelta
import pandas as pd #use pandas dataframe to store downloaded data
from StringIO import StringIO
driver = webdriver.Firefox() # Optional argument, if not specified will search path.
driver.get("http://b-us.econoday.com/byweek.asp?containerId=eco-iframe-container")
time.sleep(5)
table=driver.find_element_by_xpath("html/body/table/tbody/tr[4]/td/table[1]/tbody/tr/td/table[2]/tbody/tr[2]")
#table=driver.find_element_by_class_name('eventstable')
columns=table.find_elements_by_tag_name('td')
time.sleep(1)
#option 1 get the hole column
for col in columns:
print(col.text)
#option 2 get info row by row, but information is hided in to different classes
for col in columns_list:
rows=col.find_elements_by_tag_name('div')
for row in rows:
print(row.text)
rows=col.find_elements_by_tag_name('span')
for row in rows:
print(row.text)
Результат для последней колонки новостей будет:
Market Focus »
Daniel Tarullo Speaks
10:15 AM ET
Baker-Hughes Rig Count
1:00 PM ET
John Williams Speaks
2:30 PM ET
Вы можете проанализировать эти строки. Используйте разные имена классов для поиска необходимой информации.
Комментарии:
1. Зачем вам selenium?
2. Автор вопроса запросил все предложения для достижения своей цели. Обычно я использую Selenium, потому что он обеспечивает больше функциональности (щелчок по веб-элементам в случае интерактивной веб-страницы и так далее). Иногда лучше использовать более общий подход даже для простых задач, если вы его хорошо знаете.
3. Selenium работает мучительно медленно и на самом деле последнее, что я когда-либо пытался использовать, в нем нет динамического содержимого, поэтому здесь нет варианта его использования.
4. Я подумал, что это интересно. Я, вероятно, также не стал бы использовать Selenium в этом случае, но это не означает, что подобный ответ должен быть немедленно удален.
Ответ №3:
Есть один td с идентификатором highlight_today, все дочерние элементы содержатся в теге, поэтому вы просто нажимаете на него, и если вы хотите выполнить итерацию по дочерним элементам, вы бы вызвали find_all:
import requests
from bs4 import BeautifulSoup
url_to_scrape = 'http://b-us.econoday.com/byweek.asp?containerId=eco-iframe-container'
r = requests.get(url_to_scrape)
html = r.content
soup = BeautifulSoup(html, "html.parser")
event = soup.find('td', {'id': "highlight_today"})
for tag in event.find_all():
print(tag)
Что дало бы вам:
<div class="econoitems"><br/><span class="econoitems"><a href="byshoweventfull.asp?fid=476407amp;amp;cust=b-usamp;amp;year=2016amp;amp;lid=0amp;amp;containerId=eco-iframe-containeramp;amp;prev=/byweek.asp#top">Market Focus <span class="econo-item-arrow">»</span></a></span><br/></div>
<br/>
<span class="econoitems"><a href="byshoweventfull.asp?fid=476407amp;amp;cust=b-usamp;amp;year=2016amp;amp;lid=0amp;amp;containerId=eco-iframe-containeramp;amp;prev=/byweek.asp#top">Market Focus <span class="econo-item-arrow">»</span></a></span>
<a href="byshoweventfull.asp?fid=476407amp;amp;cust=b-usamp;amp;year=2016amp;amp;lid=0amp;amp;containerId=eco-iframe-containeramp;amp;prev=/byweek.asp#top">Market Focus <span class="econo-item-arrow">»</span></a>
<span class="econo-item-arrow">»</span>
<br/>
<br/>
<div class="itembreak"></div>
<br/>
<span class="econoarticles"><a href="byshoweventfull.asp?fid=476382amp;amp;cust=b-usamp;amp;year=2016amp;amp;lid=0amp;amp;containerId=eco-iframe-containeramp;amp;prev=/byweek.asp#top">Daniel Tarullo Speaks<br/></a></span>
<a href="byshoweventfull.asp?fid=476382amp;amp;cust=b-usamp;amp;year=2016amp;amp;lid=0amp;amp;containerId=eco-iframe-containeramp;amp;prev=/byweek.asp#top">Daniel Tarullo Speaks<br/></a>
<br/>
HTML на самом деле сломан, поэтому вам понадобится либо lxml, либо html5lib для синтаксического анализа i. Затем, чтобы получить то, что вы хотите, вам нужно найти промежутки с econoarticles
классом и проделать немного дополнительной работы, чтобы получить времена:
url_to_scrape = 'http://b-us.econoday.com/byweek.asp?containerId=eco-iframe-container'
r = requests.get(url_to_scrape)
html = r.content
soup = BeautifulSoup(html, "lxml")
event = soup.find('td', {'id': "highlight_today"})
for span in event.select("span.econoarticles"):
speaker, time, a = span.text, span.find_next_sibling(text=True), span.a["href"]
print(speaker, time, a)
Который, если мы запустим, даст вам:
In [2]: import requests
...: from bs4 import BeautifulSoup
...: url_to_scrape = 'http://b-us.econoday.com/byweek.asp?containerId=eco-ifr
...: ame-container'
...: r = requests.get(url_to_scrape)
...: html = r.content
...: soup = BeautifulSoup(html, "lxml")
...: event = soup.find('td', {'id': "highlight_today"})
...: for span in event.select("span.econoarticles"):
...: speaker, time, a = span.text, span.find_next_sibling(text=True), spa
...: n.a["href"]
...: print(speaker, time, a)
...:
Daniel Tarullo Speaks 10:15 AM ET byshoweventfull.asp?fid=476382amp;cust=b-usamp;year=2016amp;lid=0amp;containerId=eco-iframe-containeramp;prev=/byweek.asp#top
John Williams Speaks 2:30 PM ET byshoweventfull.asp?fid=476390amp;cust=b-usamp;year=2016amp;lid=0amp;containerId=eco-iframe-containeramp;prev=/byweek.asp#top
In [3]:
если вам нужны Market Focus
и URL для этого, просто добавьте:
event = soup.find('td', {'id': "highlight_today"})
det = event.select_one("span.econoitems")
name, an = det.text, det.a["href"]
print(name, an )
Комментарии:
1. Спасибо @PadraicCunningham, это идеально подходит для моих целей. После попыток установить lxml (наконец-то разобрался). Это прекрасно работает. Просто понадобилась одна небольшая правка, чтобы я мог получить все, что искал:
for span in event.select("span.econoarticles, div.econoevents"):