Я пытаюсь получить данные о поездке Citibike из Интернета. Поскольку есть несколько файлов, которые я хочу загрузить, я подумал, что лучше автоматизировать это с помощью python, получив доступ к нужным ссылкам, а затем используя другие методы для их загрузки.
вот мой код:
url = 'https://s3.amazonaws.com/tripdata/index.html'
html_source = requests.get(url).text
soup = BeautifulSoup(html_source, "html.parser")
soup.prettify()
# I'm successful until I add '.find_all('tr')' at the end
citibikedata = soup.find('tbody', id = "tbody-content").find_all('tr')
print(citibikedata)
При попытке распечатать получаю пустой list
. Если я делаю длину (len
), я получаю 0.
Однако, если я уберу find_all()
, я получу результаты только для tbody-content
.
Я подозреваю, что по какой-то причине я не могу получить доступ к тегу tr
. Между тем, есть еще один уровень тега, «td», к которому я должен получить доступ, чтобы получить данные, которые я действительно ищу, а именно href
и текст в теге a
.
Пожалуйста, что мне не хватает, я буду признателен за вашу помощь. Спасибо заранее
Я не смог найти онлайн-ресурсы, на которых обращались к тегам без классов, что, как я подозреваю, связано с проблемой. Возможно, это не так.
Вам нужна помощь от селена:
#pip install selenium
from selenium import webdriver
from bs4 import BeautifulSoup
import time
url = "https://s3.amazonaws.com/tripdata/index.html"
with webdriver.Chrome() as driver:
driver.get(url)
time.sleep(5)
tag = BeautifulSoup(driver.page_source, "html.parser").find_all("a")
links = [link.get("href") for link in tag if link.get("href")]
Выход :
#links
['https://s3.amazonaws.com/tripdata/201306-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201307-201402-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201307-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201308-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201309-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201310-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201311-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201312-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201401-citibike-tripdata.zip',
...
Этот ответ сработал, и я хотел бы отметить его тоже, но я могу отметить только один. Я выбрал ответ от @HedgeHog по двум причинам: 1. Он с наименьшим количеством строк кода 2. Я знаком с BeautifulSoup, а не с Selenium, который используется здесь. Преимущество этого ответа: 1. Selenium лучше подходит для динамической очистки сайта. Кое-что, что я узнал в этом процессе и поэтому включу в свой план обучения. Большое спасибо
Многие дороги ведут в ром — ваше объяснение позволяет легко понять, почему вы выбрали именно свою, и, возможно, вы выберете другую в другом проекте. Чтобы выразить свое спортивное мастерство, найдите минутку и прочитайте stackoverflow.com/help/привилегии/голосование, это также позволит вам соблюдать любые / другие полезные ответы.
В приведенном выше коде, если вы проверите:
citibikedata = soup.find('tbody', id = "tbody-content")
print(citibikedata)
>> <tbody id = "tbody-content">
</tbody>
Хотя вы можете получить тег tbody
, он не содержит никаких данных внутри, и вы получаете пустой список, когда пытаетесь найти в нем теги tr
.
Но вы можете достичь своей цели, используя Selenium.
Вот как вы можете это сделать:
from selenium.webdriver import Chrome
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
import selenium.webdriver.support.expected_conditions as EC
from bs4 import BeautifulSoup
url = 'https://s3.amazonaws.com/tripdata/index.html'
driver = Chrome()
driver.get(url)
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, 'tbody#tbody-content')))
html_source = driver.page_source
soup = BeautifulSoup(html_source, "html.parser")
citibikedata = soup.find('tbody', id = "tbody-content").find_all('tr')
print(citibikedata)
Ситибайкданные:
[<tr>
<td><i class = "icon-file i-file-or-folder" style = "margin-left:calc((1 * 16px) + 4px);"></i>
<a href = "https://s3.amazonaws.com/tripdata/201306-citibike-tripdata.zip">201306-citibike-tripdata.zip</a>
</td>
<td>Apr 30th 2018, 08:18:55 pm</td>
<td>16.79 MB</td>
<td>ZIP file</td>
</tr>,
...
...
<tr>
<td><i class = "icon-file i-file-or-folder" style = "margin-left:calc((1 * 16px) + 4px);"></i>
<a href = "https://s3.amazonaws.com/tripdata/index.html">index.html</a>
</td>
<td>Jan 19th 2017, 05:23:41 am</td>
<td>6 KB</td>
<td>HTML file</td>
</tr>
]
Основная проблема здесь в том, что данные, как уже упоминалось, загружаются динамически, поэтому вы можете получить их из источника, из которого они получены.
https://s3.amazonaws.com/tripdata предоставит XML-файл, содержащий ваши данные, просто повторите его элементы и выберите свои URL-адреса.
import requests
from bs4 import BeautifulSoup
base_url = 'https://s3.amazonaws.com/tripdata/'
links = [
base_url+key.text
for key in BeautifulSoup(requests.get(base_url).text).select('Key')
]
links
['https://s3.amazonaws.com/tripdata/201306-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201307-201402-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201307-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201308-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201309-citibike-tripdata.zip',
'https://s3.amazonaws.com/tripdata/201310-citibike-tripdata.zip',...]
Основываясь на вашем комментарии, вы можете использовать dict
или list
из dicts
:
import requests
from bs4 import BeautifulSoup
base_url = 'https://s3.amazonaws.com/tripdata/'
data = []
for e in BeautifulSoup(requests.get(base_url).text).select('Contents'):
data.append({
'url':base_url+e.key.text,
'date': e.lastmodified.text
})
data
Большое спасибо за вашу помощь @HedgeHog. Мне тоже нужна дата. Я могу либо использовать тег «LastModified», либо удалить ключ для года/мм (например, 201306), любой из этих способов мне подходит. Мой вопрос: как мне добиться любой из них и даты, чтобы сопровождать ссылку как одну и ту же запись, в то время как между каждой последующей записью есть пробел?
Он несколько отклоняется от ОП и поэтому должен быть поставлен как новый вопрос именно с этой целью. Но я расширил свой ответ, не стесняйтесь взглянуть на него.
Все эти элементы
tr
загружаются динамически. Их нет в исходном HTML.