@domanskiy

Почему парсер всех внутренних ссылок сайта на Python не хочет парсить некоторые сайты?

Код парсера:
from urllib.parse import urlparse
from bs4 import BeautifulSoup
import requests
import lxml
DOMAIN = 'apexair.ru'
HOST = 'http://' + DOMAIN
FORBIDDEN_PREFIXES = ['#', 'tel:', 'mailto:']
links = set()  # множество всех ссылок
headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
response = requests.get(HOST, headers=headers)
# print(response.content)

def add_all_links_recursive(url, maxdepth=1):
    # print('{:>5}'.format(len(links)), url[len(HOST):])

    # глубина рекурсии не более `maxdepth`

    # список ссылок, от которых в конце мы рекурсивно запустимся
    links_to_handle_recursive = []
    # получаем html код страницы
    request = requests.get(url, headers=headers)
    # парсим его с помощью BeautifulSoup
    soup = BeautifulSoup(request.content, 'lxml')
    # рассматриваем все теги <a>

    for tag_a in soup.find_all('a'):
        link = tag_a['href']


        # если ссылка не начинается с одного из запрещённых префиксов
        if all(not link.startswith(prefix) for prefix in FORBIDDEN_PREFIXES):
            # проверяем, является ли ссылка относительной
            # например, `/oplata` --- это относительная ссылка
            # `http://101-rosa.ru/oplata` --- это абсолютная ссылка
            if link.startswith('/') and not link.startswith('//'):
                # преобразуем относительную ссылку в абсолютную
                link = HOST + link
            # проверяем, что ссылка ведёт на нужный домен
            # и что мы ещё не обрабатывали такую ссылку
            if urlparse(link).netloc == DOMAIN and link not in links:
                links.add(link)
                links_to_handle_recursive.append(link)

    if maxdepth > 0:
        for link in links_to_handle_recursive:
            add_all_links_recursive(link, maxdepth=maxdepth - 1)


def main():
    add_all_links_recursive(HOST + '/')
    for link in links:
        print(link)


if __name__ == '__main__':
    main()


Не на всех сайтах работает.
Например не хочет работать с :
euroclimate.org
apexair.ru

Ошибка:
Traceback (most recent call last):
  File "E:/Users/Alex/Documents/MyPyProj/parser-links.py", line 57, in <module>
    main()
  File "E:/Users/Alex/Documents/MyPyProj/parser-links.py", line 51, in main
    add_all_links_recursive(HOST + '/')
  File "E:/Users/Alex/Documents/MyPyProj/parser-links.py", line 47, in add_all_links_recursive
    add_all_links_recursive(link, maxdepth=maxdepth - 1)
  File "E:/Users/Alex/Documents/MyPyProj/parser-links.py", line 28, in add_all_links_recursive
    link = tag_a['href']
  File "C:\Python38\lib\site-packages\bs4\element.py", line 1321, in __getitem__
    return self.attrs[key]
KeyError: 'href'


С чем такое может быть связано? МОжет от того что некоторые ссылке на сайтах возвращают None? т.е. href=""
  • Вопрос задан
  • 2364 просмотра
Решения вопроса 1
trapwalker
@trapwalker Куратор тега Python
Программист, энтузиаст
На в каждом теге "a" есть `href`.
from urllib.parse import urlparse
from bs4 import BeautifulSoup
import requests
import lxml
DOMAIN = 'apexair.ru'
HOST = 'http://' + DOMAIN
FORBIDDEN_PREFIXES = ['#', 'tel:', 'mailto:']
links = set()  # множество всех ссылок
headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
response = requests.get(HOST, headers=headers)
# print(response.content)

def add_all_links_recursive(url, maxdepth=1):
    # print('{:>5}'.format(len(links)), url[len(HOST):])

    # глубина рекурсии не более `maxdepth`

    # список ссылок, от которых в конце мы рекурсивно запустимся
    links_to_handle_recursive = []
    # получаем html код страницы
    request = requests.get(url, headers=headers)
    # парсим его с помощью BeautifulSoup
    soup = BeautifulSoup(request.content, 'lxml')
    # рассматриваем все теги <a>

    for tag_a in soup.find_all('a', href=lambda v: v is not None):
        link = tag_a['href']

        # если ссылка не начинается с одного из запрещённых префиксов
        if all(not link.startswith(prefix) for prefix in FORBIDDEN_PREFIXES):
            # проверяем, является ли ссылка относительной
            # например, `/oplata` --- это относительная ссылка
            # `http://101-rosa.ru/oplata` --- это абсолютная ссылка
            if link.startswith('/') and not link.startswith('//'):
                # преобразуем относительную ссылку в абсолютную
                link = HOST + link
            # проверяем, что ссылка ведёт на нужный домен
            # и что мы ещё не обрабатывали такую ссылку
            if urlparse(link).netloc == DOMAIN and link not in links:
                links.add(link)
                links_to_handle_recursive.append(link)

    if maxdepth > 0:
        for link in links_to_handle_recursive:
            add_all_links_recursive(link, maxdepth=maxdepth - 1)


def main():
    add_all_links_recursive(HOST + '/')
    for link in links:
        print(link)


if __name__ == '__main__':
    main()
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы