Какие ссылки должны входить в sitemap?
Мне необходимо написать (без использования посторонних библиотек) генератор карты сайта.
Я написал код, но работает он не для всех сайтов. Проблема заключается в том, что при проходе по ссылкам появляются бесконечные рекурсии. На сайте www.sitemaps.org нету ни слова про то какие ссылки должны входить, а какие нет. Вопрос в том, какие ссылки явлеяются нужными для составления sitemap.xml?
import requests
import pprint
import re
import time
import threading
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin, urlunsplit, urlsplit
from xml.etree import cElementTree as ET
from functools import lru_cache
class SiteMap(object):
def __init__(self, site):
self.site = self.__secure(site)
self.urls = list()
self.hostname = ''
self.regex = r"https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)"
self.excluded_resources = (".epub", ".mobi", ".docx", ".doc", ".opf", ".7z", ".ibooks", ".cbr", ".avi", ".mkv", ".mp4", ".jpg", ".jpeg", ".png", ".gif" ,".pdf", ".iso", ".rar", ".tar", ".tgz", ".zip", ".dmg", ".exe")
@lru_cache()
def __get_urls_from_soup(self, soup):
for sp in soup.find_all('a', href=True):
link = sp.get('href')
yield self.__get_absolute_url(link)
def __secure(self, url):
https_url = url.replace('http://', 'https://')
with requests.Session() as session:
response = session.get(https_url)
if response.status_code == 200:
return https_url
else:
return url
def __get_absolute_url(self, url):
if not url.startswith(self.site):
return urljoin(self.site, url)
else:
return url
def __is_signin_or_singup(self, url):
link = urlparse(url)
if 'login' in link.path or 'signup' in link.path or 'signin' in link.path:
return True
else:
return False
def __excluded_resources(self, url):
for resource in self.excluded_resources:
if url.endswith(resource):
return True
return False
def __get_urls_from_site(self, url, urls):
url = self.__get_absolute_url(url)
response = None
with requests.Session() as session:
try:
response = session.get(url)
except requests.TooManyRedirects:
response = session.get(url, allow_redirects=False)
finally:
if not response:
return urls
elif response.status_code != 200:
return urls
soup = BeautifulSoup(response.text, 'html.parser')
for link in self.__get_urls_from_soup(soup):
if link in urls or not link.startswith(self.site) or not re.fullmatch(self.regex, link) or self.__is_signin_or_singup(link) or self.__excluded_resources(link):
continue
with open(self.hostname, 'a', encoding='utf-8') as file:
file.write(link + '\n')
urls.append(link)
urls = self.__get_urls_from_site(link, urls)
return urls
def create(self):
urls = list()
urls.append(self.site)
parse = urlparse(self.site)
self.hostname = parse.hostname
self.urls = self.__get_urls_from_site(self.site, urls)
pprint.pprint(self.urls)
def save(self, filename):
urlset = ET.Element("urlset", xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
for url in self.urls:
link = ET.SubElement(urlset, "url")
ET.SubElement(link, "loc").text = url
tree = ET.ElementTree(urlset)
tree.write(filename)
if __name__ == '__main__':
threads = dict()
sitemaps = list()
sites = [
"http://crawler-test.com/",
"http://google.com/",
"https://vk.com",
"https://yandex.ru",
"https://stackoverflow.com"
]
for site in sites:
sitemap = SiteMap(site)
thread = threading.Thread(target=sitemap.create)
thread.start()
threads[thread.ident] = dict({
'thread': thread,
'time_start': int(time.time()),
'time_end': 0})
sitemaps.append(sitemap)
for thread in threads:
threads[thread]['thread'].join()
threads[thread]['time_end'] = int(time.time())
print(f"Time to process thread #{thread} is {threads[thread]['time_end'] - threads[thread]['time_start']}")
for sitemap in sitemaps:
sitemap.save(f"{sitemap.hostname}.xml")
print(f"Count of urls {sitemap.hostname} is {len(sitemap.urls)}")
Сайты с которыми код работает - "http://crawler-test.com/", "http://google.com/", "https://vk.com"
Сайты с которыми я вхожу в бесконечную рекурсию - "https://yandex.ru", "https://stackoverflow.com"