Почему это извлечение отлично работает на примере, но не на реальном URL?

#python-3.x #beautifulsoup

#python-3.x #beautifulsoup

Вопрос:

Я пытаюсь извлечь содержимое href in class a , которое находится внутри <td class="DataZone"> . Это работает в приведенном ниже примере

 from bs4 import BeautifulSoup

text = '''
<td class="DataZone"><div id="Content_CA_DI_0_DataZone">
<div style="font:bold 8pt 'Courier New';letter-spacing:-1px">
<a href="Browse-A">A</a> <a href="Browse-B">B</a> <a href="Browse-C">C</a> <a href="Browse-D">D</a> 
</div>
</div></td>
'''

soup = BeautifulSoup(text, 'html.parser')

[tag.attrs['href'] for tag in soup.select('td.DataZone a')]
  

, и результат ['Browse-A', 'Browse-B', 'Browse-C', 'Browse-D'] . Когда я применяю это к реальному URL, это, к сожалению, не работает

 import requests
session = requests.Session()
from bs4 import BeautifulSoup

url = 'https://www.thefreedictionary.com'
headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0'}
r = session.get(url, headers = headers) 
soup = BeautifulSoup(r.content, 'html.parser')

[tag.attrs['href'] for tag in soup.select('td.DataZone a')]
  

Возвращает ошибку

 ---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-12-0a06dde2d97b> in <module>
      4 soup = BeautifulSoup(r.content, 'html.parser')
      5 
----> 6 [tag.attrs['href'] for tag in soup.select('td.DataZone a')]

<ipython-input-12-0a06dde2d97b> in <listcomp>(.0)
      4 soup = BeautifulSoup(r.content, 'html.parser')
      5 
----> 6 [tag.attrs['href'] for tag in soup.select('td.DataZone a')]

KeyError: 'href'
  

Очевидно, что источник URL похож на пример

введите описание изображения здесь

Не могли бы вы, пожалуйста, объяснить, почему возникает такая ошибка?


Обновление: Для меня странно, что [x['href'] for x in soup.select('td.DataZone a[href^=Browse]')] работает нормально, но не [x['href'] for x in soup.select('td.DataZone a')] . Пожалуйста, также уточните проблему.

Ответ №1:

Вы получаете ошибку, потому что есть много td.Datazone тегов, и внутри одного из тегов есть <a>Google </a> — который без href .

Вы можете выбрать с помощью td.DataZone a[href] , чтобы выбрать только <a> теги с href атрибутом:

 print( [tag.attrs['href'] for tag in soup.select('td.DataZone a[href]')] )
  

Комментарии:

1. Ваш ответ все проясняет. Большое вам спасибо!

Ответ №2:

Похоже, что не у всех <a> тегов есть href атрибут. Попробуйте это вместо этого.

 l = [tag.attrs['href'] for tag in soup.select('td.DataZone a') if 'href' in tag.attrs]
print(*l, sep = 'n')
  

Вы также можете сделать это.

 l = [tag.attrs['href'] for tag in soup.select('td.DataZone a[attr="href"]')]
print(*l, sep = 'n')
  

Комментарии:

1. Я только что проверил и подтвердил, что all <a> имеет href атрибут.

2. Прошу прощения за мой предыдущий неаккуратный комментарий. Вы правы.

Ответ №3:

Дело в том, что вы используете неправильный CSS селектор.

 import requests
from bs4 import BeautifulSoup


def main(url):
    r = requests.get(url)
    soup = BeautifulSoup(r.content, 'html.parser')
    target = [x['href'] for x in soup.select("a[href^=Browse]")]
    print(target)


main("https://www.thefreedictionary.com/")
  

Или:

 target = [x for x in soup.select("td.DataZone a[href^=Browse]")]
  

Вывод:

 ['Browse-A', 'Browse-B', 'Browse-C', 'Browse-D', 'Browse-E', 'Browse-F', 'Browse-G', 'Browse-H', 'Browse-I', 'Browse-J', 'Browse-K', 'Browse-L', 'Browse-M', 'Browse-N', 'Browse-O', 'Browse-P', 'Browse-Q', 'Browse-R', 'Browse-S', 'Browse-T', 'Browse-U', 'Browse-V', 'Browse-W', 'Browse-X', 'Browse-Y', 'Browse-Z']
  

Обновление на основе требований пользователя в комментарии:

 import requests
from bs4 import BeautifulSoup


def main(url):
    r = requests.get(url)
    soup = BeautifulSoup(r.content, 'html.parser')
    for item in soup.select("td.DataZone"):
        for x in item.findAll(href=True):
            print(x['href'])


main("https://www.thefreedictionary.com/")
  

Комментарии:

1. Не могли бы вы, пожалуйста, объяснить, как я использую неправильный CSS селектор?

2. @LAD Действительно, согласно вашему img , так что нужные данные доступны в пределах anchor >> a , где они хранятся, href начиная с Просмотра

3. Я не понимаю. Я думал, что это Browse-A значение href . Я намерен использовать все значение href , даже если оно не содержит Browse . Я имею в виду, что, если есть некоторые, a чьи href не содержат Browse .

4.@LAD итак, ваш вопрос заключается в получении значений anchor href всякий раз, когда оно находится под td.DataZone ?

5. Да, это именно то, что я хочу :)))