piolvior
@piolvior
начинающий продуктовый аналитик

Ошибка с перенаправлением: как скачать файл с веб.страницы в формате pdf?

Пытаюсь скачать pdf файл. Я использую модуль request. Вот код.

url = 'https://unistream.ru/upload/iblock/230/230283e15180d590198137eba4e70644.PDF'
r = requests.get(url, allow_redirects=False)  
pdf_url = r.url 

with open('C:\\Users\\piolv\\Desktop\\pdf_folder\\work_file.PDF', 'wb') as f:
    f.write(r.content)
    print(r.content)


Именно эта ссылка открывается в браузере, но скачать ее не получается, скачивается пустой файл - как html документ. 5кб Как я выяснил, сайт делает редирект - код статуса 302. Но стандартным способом allow_redirects=False у меня не получается загрузить этот файл. Что я делаю не так? Где ошибка?
  • Вопрос задан
  • 263 просмотра
Решения вопроса 1
deepblack
@deepblack Куратор тега Python
Дело в том что на этом сайте есть защита от ботов.
И скачивается не пустой файл как html, а довольно интересный код на JS (внутри этого html файла):

Посмотреть содержимое

var utm_set = null;

function setup_utm() {
    if (utm_set == null) return null;
    var i = 0;
    var p = document.createElement("a");
    p.href = document.referrer;
    for (i = 0; i < utm_set.length; i++) {
        if (p.hostname === utm_set[i]["host"] || p.hostname.indexOf(utm_set[i]["host"] + '.') === 0 || p.hostname.indexOf('www.' + utm_set[i]["host"] + '.') === 0) {
            return utm_set[i]["args"];
        }
    }
    return null;
}

function fixedEncodeURIComponent(str) {
    return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
        return "%" + c.charCodeAt(0).toString(16);
    });
}

function get_jhash(b) {
    var x = 123456789;
    var i = 0;
    var k = 0;
    for (i = 0; i < 1677696; i++) {
        x = ((x + b) ^ (x + (x % 3) + (x % 17) + b) ^ i) % 16776960;
        if (x % 117 === 0) {
            k = (k + 1) % 1111;
        }
    }
    return k;
}


function get_param(store, type, id) {
    var o = document.cookie.split(';');
    var p = undefined;
    for (var i = 0; i < o.length; i++) {
        if (o[i].indexOf(store) !== -1) {
            var a = o[i].split('=');
            if (a.length > 1) {
                var q = a[1].split(',');
                if (q.length > id) {
                    p = q[id];
                }
            }
        }
    }
    if (p === undefined) {
        if (type === "int") {
            return 0;
        }
        if (type === "str") {
            return "";
        }
    }
    if (type === "int") {
        return parseInt(p);
    }
    return p + "";
}

function get_utm_medium() {
    var mediums = {
        "organic": ["yandex", "google", "bing", "search.yahoo", "yahoo"],
        "referral": null
    };

    var m, a, v, f = 0;
    var p = document.createElement("a");
    p.href = document.referrer;
    for (m in mediums) {
        a = mediums[m];
        if (a == null) {
            break;
        }
        f = 0;
        for (var i = 0; i < a.length; i++) {
            v = a[i];
            if (p.hostname.indexOf(v + '.') === 0 || p.hostname.indexOf('www.' + v + '.') === 0) {
                f = 1;
                break;
            }
        }
        if (f === 1) {
            break;
        }
    }
    return m;

}

function mini_hostname(hostname, medium) {
    if (hostname === undefined || hostname === "") {
        return hostname;
    }
    hostname = hostname.replace("www.", "");
    if (medium === "organic") {
        if (get_param("__js_p_", "int", 3) === 1) {
            hostname = hostname.split(".")[0];
        }
    }
    return hostname;
}

function construct_utm_uri(disable_utm) {

    var p = document.createElement("a");
    p.href = document.referrer;
    if (p.href === "") {
        return window.location.href;
    }

    var ref = p.hostname.replace("www.", "");

    var loc = window.location.hostname.replace("www.", "");
    if (loc === ref) {
        return window.location.href;
    }
    if (disable_utm === 1) {
        return window.location.href;
    }
    if (window.location.href.indexOf("utm_") !== -1 || window.location.href.indexOf("gclid=") !== -1 || window.location.href.indexOf("yclid=") !== -1) {
        return window.location.href;
    }
    var uri = window.location.href;
    if (uri.indexOf("?") !== -1) {
        uri += "&";
    } else {
        uri += "?";
    }
    var medium = get_utm_medium();
    var hostname = mini_hostname(p.hostname, medium);
    var args = setup_utm();
    if (args != null) {
        uri += args;
    } else {
        uri += "utm_source=" + hostname + "&utm_medium=" + medium + "&utm_campaign=" + hostname + "&utm_referrer=" + hostname;
    }
    return uri;
}

setTimeout(function() {
    var code = get_param("__js_p_", "int", 0);
    var age = get_param("__js_p_", "int", 1);
    var sec = get_param("__js_p_", "int", 2);
    var disable_utm = get_param("__js_p_", "int", 4);
    var jhash = get_jhash(code);
    document.cookie = "__jhash_=" + jhash + ";max-age=" + age + "; " + (sec ? "SameSite=None;Secure;" : "") + " Path=/";
    document.cookie = "__jua_=" + fixedEncodeURIComponent(navigator.userAgent) + ";max-age=" + age + "; " + (sec ? "SameSite=None;Secure;" : "") + " Path=/";
    window.location.href = construct_utm_uri(disable_utm);
    if (window.location.hash) {
        window.location.reload();
    }
}, 1000);



Коротко и с некоторыми неточностями:
  1. Браузер делает запрос, получает куку и тот самый html c js кодом внутри
  2. Код производит некоторые вычисления, ставит еще некоторые куки, после этого происходит повторный запрос к серверу
  3. На сервере куки валидируются и отдается либо нормальное содержимое либо тот самый html файл снова


Скрины со вкладки Cookies консоли разработчика
636b53c330230551365215.png
636b53e570e62600722645.png



Тут несколько вариантов решения:
  1. Сходить на сайт через браузер, скопировать куки, подставить их в запрос requests (естественно куки протухнут и надо будет повторять операцию)
  2. Разобрать как работает скрипт и эмулировать его работу на Python
  3. Взять что-то наподобие Selenium webdriver и решить задачу с помощью него
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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