D
D
domanskiy2020-02-29 23:39:13
Python
domanskiy, 2020-02-29 23:39:13

Why doesn't the Python parser for all internal site links want to parse some sites?

Parser code:

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()


Doesn't work on all sites.
For example, does not want to work with:
euroclimate.org
apexair.ru

Error:
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'


With what it can be connected? Maybe because some links on sites return None? those. href=""

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Sergey Pankov, 2020-03-02
@domanskiy

On every "a" tag there is 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()

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question