Регулярно проверяйте, есть ли ссылка на файл - PullRequest
5 голосов
/ 07 марта 2019

Как проверить, является ли данная ссылка (URL) на файл или другую веб-страницу?

Я имею в виду:

В настоящее время я являюсьделать это с довольно хакерской многоэтапной проверкой, и это также требует преобразования относительно абсолютных ссылок, добавления префикса http, если он отсутствует, и удаления '#' якорных ссылок / параметров для работы.Я также не уверен, внесу ли я в белый список все возможные расширения страниц, которые существуют .

import re
def check_file(url):
    try:
        sub_domain = re.split('\/+', url)[2] # part after '2nd slash(es)''
    except:
        return False # nothing = main page, no file
    if not re.search('\.', sub_domain):
        return False # no dot, no file
    if re.search('\.htm[l]{0,1}$|\.php$|\.asp$', sub_domain):
        return False # whitelist some page extensions
    return True

tests = [
    'https://www.stackoverflow.com',
    'https://www.stackoverflow.com/randomlink',
    'https:////www.stackoverflow.com//page.php',
    'https://www.stackoverflow.com/page.html',
    'https://www.stackoverflow.com/page.htm',
    'https://www.stackoverflow.com/file.exe',
    'https://www.stackoverflow.com/image.png'
]

for test in tests:
    print(test + '\n' + str(check_file(test)))
# False: https://www.stackoverflow.com
# False: https://www.stackoverflow.com/randomlink
# False: https:////www.stackoverflow.com//page.php
# False: https://www.stackoverflow.com/page.html
# False: https://www.stackoverflow.com/page.htm
# True: https://www.stackoverflow.com/file.exe
# True: https://www.stackoverflow.com/image.png

Существует ли чистое решение для единственного соответствия регулярному выражению для этой проблемыили библиотека с установленной функцией , чтобы сделать это?Я предполагаю, что кто-то должен был столкнуться с этой проблемой до меня, но, к сожалению, я не смог найти решение здесь, на SO или в другом месте.

Ответы [ 2 ]

3 голосов
/ 07 марта 2019

urlparse ваш друг.

from urllib.parse import urlparse

def check_file(url):
    path = urlparse(url).path  # extract the path component of the URL
    name = path.rsplit('/', 1)[-1]  # discard everything before the last slash

    if '.' not in name:  # if there's no . it's definitely not a file
        return False

    ext = path.rsplit('.', 1)[-1]  # extract the file extension
    return ext not in {'htm', 'html', 'php', 'asp'}

Это можно еще больше упростить с помощью модуля pathlib:

from urllib.parse import urlparse
from pathlib import PurePath

def check_file(url):
    path = PurePath(urlparse(url).path)
    ext = path.suffix[1:]

    if not ext:
        return False

    return ext not in {'htm', 'html', 'php', 'asp'}
2 голосов
/ 07 марта 2019

Ответ Аран-Фей хорошо работает на страницах с хорошим поведением, которые составляют 99,99% Интернета. Но нет правила, согласно которому URL-адрес, заканчивающийся конкретным расширением, должен разрешать содержимое определенного типа. Плохо настроенный сервер может вернуть html для запроса на страницу с именем «example.png», или он может вернуть mpeg для страницы с именем «example.php», или любую другую комбинацию типов содержимого и расширений файлов.

Самый точный способ получить информацию о типе контента для URL-адреса - это посетить этот URL-адрес и изучить тип контента в его заголовке. В большинстве библиотек с интерфейсом http есть способ извлечения только информации заголовка с сайта, поэтому эта операция должна быть относительно быстрой даже для очень больших страниц. Например, если вы используете requests, вы можете сделать:

import requests
def get_content_type(url):
    response = requests.head(url)
    return response.headers['Content-Type']

test_cases = [
    "http://www.example.com",
    "https://i.stack.imgur.com/T3HH6.png?s=328&g=1",
    "http://php.net/manual/en/security.hiding.php",
]    

for url in test_cases:
    print("Url:", url)
    print("Content type:", get_content_type(url))

Результат:

Url: http://www.example.com
Content type: text/html; charset=UTF-8
Url: https://i.stack.imgur.com/T3HH6.png?s=328&g=1
Content type: image/png
Url: http://php.net/manual/en/security.hiding.php
Content type: text/html; charset=utf-8
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...