#python #html #web-scraping #beautifulsoup
#python #HTML #веб-очистка #beautifulsoup
Вопрос:
Я пытаюсь очистить https://www.betexplorer.com/soccer/england/premier-league/fixtures / чтобы извлечь текст, содержащийся в теге ‘a’, в частности, в таблице с классом «table-main», затем для каждой строки внутри него. Первый td содержит текст с двумя названиями команд, с классом td «h-text-left». Не уверен, связана ли проблема с моим циклом или нет, но сообщение об ошибке, которое я получаю, похоже, что я неправильно использую bs4 в своей последней строке в цикле.
Я могу очистить каждый tr в таблице с помощью класса «table-main», а затем, кроме того, каждый td с классом «h-text-left». Я нахожусь в тупике, хотя при попытке извлечь только элементы «a», даже не текст «a».
import requests
from bs4 import BeautifulSoup
headers = {'User-Agent':
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36'}
r = requests.get('https://www.betexplorer.com/soccer/england/premier-league/fixtures/', headers=headers)
c = r.content
soup = BeautifulSoup(c)
fixture_table = soup.find('table', attrs = {'class': 'table-main'})
for tr in soup.find_all('tr'):
match_tds = tr.find_all('td', attrs = {'class': 'h-text-left'})
matches = match_tds.find_all('a')
Последняя строка, когда я пытаюсь найти все теги «a», выдает следующую ошибку:
... matches = match_tds.find_all('a')
...
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
File "C:UsersGlyptAppDataLocalProgramsPythonPython36-32libsite-packagesbs4element.py", line 1884, in __getattr__
"ResultSet object has no attribute '%s'. You're probably treating a list of items like a single item. Did you call find_all() when you meant to call find()?" % key
AttributeError: ResultSet object has no attribute 'find_all'. You're probably treating a list of items like a single item. Did you call find_all() when you meant to call find()?
>>>
Ответ №1:
Вы можете сократить это до гораздо более быстрого метода выбора, используя один класс. Все ссылки имеют одно и то же имя класса, поэтому вы можете передать его select
в понимание списка, чтобы предоставить вам все ссылки.
import requests
from bs4 import BeautifulSoup
r = requests.get('https://www.betexplorer.com/soccer/england/premier-league/fixtures/')
soup = BeautifulSoup(r.content, 'lxml')
matches = [item['href'] for item in soup.select('.in-match')]
Шансы
import requests
from bs4 import BeautifulSoup
r = requests.get('https://www.betexplorer.com/soccer/england/premier-league/fixtures/')
soup = BeautifulSoup(r.content, 'lxml')
odds = [item['data-odd'] for item in soup.select('.table-main__odds [data-odd]')]
print(odds)
Комментарии:
1. Я пробую этот подход сейчас, но на самом деле я пытаюсь извлечь текст ссылки, а не атрибут href. Я попытался изменить ваш пример, чтобы извлечь текст коэффициентов, но при его печати я не получаю никаких выходных данных, т.е. [] <td class=»table-main__odds» data-oid=»33jkrxv464x0x7k7pm»>» onclick=»my_selections_click(‘1×2’, ‘soccer’, ‘action=3amp;amp;matchid=tKLzuv9Mamp;amp;outcomeid=33jkrxv464x0x7k7pmamp;amp;otheroutcomes=33jkrxv498x0x0,33jkrxv464x0x7k7pn’); » title=»Добавить в избранное»>2.08 </a> </td>
2. Извините, у этих ссылок нет класса ‘.in-match’ или, скорее, вообще никакого класса. Однако я попытался разобрать атрибут «title», который, похоже, всегда является «Добавить к моим выборкам». Однако при попытке распечатать список совпадений после этого я не получаю никаких результатов.
3. Прошу прощения за ужасное форматирование, но для примера элемента a, который я привел выше, я хочу извлечь текст «2.08» из элемента a.
4. Вы бы изменили на item.text для item в
5. совпадения = [item.text для элемента в soup.select(‘.in-match’)] шансы = [item.text для элемента в soup.select (‘Добавить в мои выборки’)] Первый работает так, как вы описали, однако второй не работает, когда я пытаюсь настроить таргетинг на атрибут title элементов A. Все еще выводится []
Ответ №2:
Вы должны использовать встроенную функциональность для поиска вложенных структур. Вы можете указать .css
класс с '.class_name'
помощью и найти вложенные структуры с помощью «первый селектор»> «второй селектор» (или даже больше селекторов). Вместе это будет выглядеть так:
import requests
from bs4 import BeautifulSoup
s = requests.session()
s.headers['User-Agent'] = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36'
res = s.get('https://www.betexplorer.com/soccer/england/premier-league/fixtures/')
soup = BeautifulSoup(res.text, 'html.parser')
matches = soup.select('.table-main tr td a')
for match in matches:
print(match.getText())
В строке matches = soup.select('.table-main tr td a')
будут выбраны все a
элементы, которые находятся внутри td
элемента, которые находятся внутри tr
элемента, которые находятся внутри class=table-main
элемента. Кроме того, вы можете использовать matches = soup.select('td > a')
( >
оператор), чтобы указать, что a
элемент находится непосредственно внутри td
элемента. Я полагаю, что это потенциально может значительно упростить ваш код!
Примечание, я не смог протестировать это на своем компьютере, поскольку сертификат SSL не может быть подтвержден и поднят requests.exceptions.SSLError
Ответ №3:
Чтобы получить текст, попробуйте:
for td in soup.findAll('td', attrs = {'class': 'h-text-left'}):
print(td.findAll('a')[0].text)
Ответ №4:
match_tds
это список, а не отдельный элемент — вы получаете его с tr.find_all(...)
помощью — поэтому вам нужно использовать for
цикл для запуска другого find_all()
for tr in soup.find_all('tr'):
match_tds = tr.find_all('td', attrs = {'class': 'h-text-left'})
for item in match_tds:
matches = item.find_all('a')
for a in matches:
print(a['href'])
Если вы используете find()
для получения первого элемента, вы можете использовать с другим find()
или find_all()
soup.find(...).find(...).find_all(...)
но вы не можете использовать find()
или find_all()
после find_all()
# ERROR
soup.find_all(...).find_all(...)
# ERROR
soup.find_all(...).find(...)
Комментарии:
1. Спасибо, получил именно то, что искал.