Как загрузить изображение с помощью Python 3/Selenium, если URL-адрес начинается с blob:?

При использовании web.whatsapp.de можно увидеть, что ссылка на полученное изображение может выглядеть так:

blob:https://web.whatsapp.com/3565e574-b363-4aca-85cd-2d84aa715c39

Если ссылка скопирована в адресное окно, она откроет изображение, однако, если «клякса» не указано, она просто откроет новое веб-окно WhatsApp.

Я пытаюсь загрузить изображение, отображаемое по этой ссылке.

Но использование распространенных методов, таких как использование запроса, urllib.request или даже BeautifulSoup, всегда приводит к проблемам в одном месте: «клякса» в начале URL-адреса вызовет ошибку.

Эти ответы Загрузить файл с URL-адреса BLOB-объекта с помощью Python вызовут ошибку

URLError: <urlopen error unknown url type: blob>

или ошибка

InvalidSchema: No connection adapters were found for 'blob:https://web.whatsapp.com/f50eac63-6a7f-48a4-a2b8-8558a9ffe015'

(используя BeatufilSoup)

Используя нативный подход, например:

import requests

url = 'https://web.whatsapp.com/f50eac63-6a7f-48a4-a2b8-8558a9ffe015'
fileName = 'test.png'
req = requests.get(url)
file = open(fileName, 'wb')
for chunk in req.iter_content(100000):
    file.write(chunk)
file.close()

Просто приведет к той же ошибке, что и при использовании BeautifulSoup.

Я управляю Chrome с помощью Selenium в Python, однако мне не удалось правильно загрузить изображение по предоставленной ссылке.


person Kev1n91    schedule 21.11.2017    source источник
comment
Не могли бы вы указать соответствующий источник HTML изображения, которое вы пытаетесь очистить?   -  person Bin Ury    schedule 22.11.2017
comment
web.whatsapp.com URL-ссылки с изображения будут отличаться от пользователя к пользователю, поэтому я не могу предоставить примерную ссылку.   -  person Kev1n91    schedule 22.11.2017
comment
При предварительном просмотре общих изображений на этой странице в углу появляется кнопка загрузки. Вы можете попробовать нажать эту кнопку щелчком мыши в Selenium, что должно предложить браузеру загрузить ресурс BLOB-объекта. Может потребоваться некоторая настройка для автоматической загрузки по ссылке, которой я поделился ниже.   -  person Bin Ury    schedule 22.11.2017


Ответы (3)


Большой двоичный объект — это файлоподобный объект необработанных данных, хранящихся в браузере.

Вы можете увидеть их на chrome://blob-internals/

С помощью Selenium можно получить содержимое большого двоичного объекта с помощью внедрения скрипта. Однако вам придется соблюдать политику перекрестного происхождения, запустив скрипт на странице/домене, создавшем большой двоичный объект:

def get_file_content_chrome(driver, uri):
  result = driver.execute_async_script("""
    var uri = arguments[0];
    var callback = arguments[1];
    var toBase64 = function(buffer){for(var r,n=new Uint8Array(buffer),t=n.length,a=new Uint8Array(4*Math.ceil(t/3)),i=new Uint8Array(64),o=0,c=0;64>c;++c)i[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c);for(c=0;t-t%3>c;c+=3,o+=4)r=n[c]<<16|n[c+1]<<8|n[c+2],a[o]=i[r>>18],a[o+1]=i[r>>12&63],a[o+2]=i[r>>6&63],a[o+3]=i[63&r];return t%3===1?(r=n[t-1],a[o]=i[r>>2],a[o+1]=i[r<<4&63],a[o+2]=61,a[o+3]=61):t%3===2&&(r=(n[t-2]<<8)+n[t-1],a[o]=i[r>>10],a[o+1]=i[r>>4&63],a[o+2]=i[r<<2&63],a[o+3]=61),new TextDecoder("ascii").decode(a)};
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(){ callback(toBase64(xhr.response)) };
    xhr.onerror = function(){ callback(xhr.status) };
    xhr.open('GET', uri);
    xhr.send();
    """, uri)
  if type(result) == int :
    raise Exception("Request failed with status %s" % result)
  return base64.b64decode(result)

bytes = get_file_content_chrome(driver, "blob:https://developer.mozilla.org/7f9557f4-d8c8-4353-9752-5a49e85058f5")
person Florent B.    schedule 22.11.2017
comment
Как сохранить этот контент в файл или воспроизвести аудио? - person Slowaways; 17.12.2020

Blob-объекты не являются реальными файлами, которые можно получить удаленно с помощью URI. . Вместо этого они представляют собой программно сгенерированные псевдо-URL-адреса, которые сопоставляются с двоичными данными, чтобы браузер мог на что-то ссылаться. т.е. нет атрибута <img> для предоставления необработанных данных, поэтому вместо этого вы создаете адрес большого двоичного объекта для сопоставления этих данных со стандартным атрибутом src.

Со страницы MDN, указанной выше:

Единственный способ прочитать содержимое из большого двоичного объекта — использовать FileReader. Следующий код считывает содержимое большого двоичного объекта как типизированный массив.

var reader = new FileReader();
reader.addEventListener("loadend", function() {
   // reader.result contains the contents of blob as a typed array
});
reader.readAsArrayBuffer(blob);
person Bin Ury    schedule 21.11.2017
comment
Спасибо за ваше понимание, я новичок в javascript - не могли бы вы сказать мне, что мне нужно вписать в качестве блоба? Ссылка, у меня есть? - person Kev1n91; 22.11.2017
comment
Если я введу команду readAsDataURL(blob:web.whatsapp.com/3565e574-b363 -4aca-85cd-2d84aa715c39), я получаю сообщение об ошибке, что аргумент не является типом blob. Примеры отличные, но все же при использовании он не определен. Вы пробовали это с примерной ссылкой из сети WhatsApp? - person Kev1n91; 22.11.2017
comment
Он ищет фактический объект Blob, а не URL-адрес. Из того, что я могу сказать, загрузка файлов с помощью безголового браузера требует некоторого обходного пути для начала (см.: blog.codecentric.de/en/2010/07/), поскольку Javascript (в целях безопасности) не предоставляет механизм для автоматической загрузки файла. Мне неясно, возможно ли программно загрузить ресурс BLOB-объектов, поскольку я еще не встречал примеров использования этого безголового браузера. - person Bin Ury; 22.11.2017

Для тех, кто пытается сделать то же самое в узле и селене, см. ниже.

var script = function (blobUrl) {
    console.log(arguments);
    var uri = arguments[0];
    var callback = arguments[arguments.length - 1];
    var toBase64 = function(buffer) {
        for(var r,n=new Uint8Array(buffer),t=n.length,a=new Uint8Array(4*Math.ceil(t/3)),i=new Uint8Array(64),o=0,c=0;64>c;++c)
            i[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c);for(c=0;t-t%3>c;c+=3,o+=4)r=n[c]<<16|n[c+1]<<8|n[c+2],a[o]=i[r>>18],a[o+1]=i[r>>12&63],a[o+2]=i[r>>6&63],a[o+3]=i[63&r];return t%3===1?(r=n[t-1],a[o]=i[r>>2],a[o+1]=i[r<<4&63],a[o+2]=61,a[o+3]=61):t%3===2&&(r=(n[t-2]<<8)+n[t-1],a[o]=i[r>>10],a[o+1]=i[r>>4&63],a[o+2]=i[r<<2&63],a[o+3]=61),new TextDecoder("ascii").decode(a)
    };
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(){ callback(toBase64(xhr.response)) };
    xhr.onerror = function(){ callback(xhr.status) };
    xhr.open('GET', uri);
    xhr.send();
}
driver.executeAsyncScript(script, imgEleSrc).then((result) => {
    console.log(result);
})

Подробное объяснение см. ниже по ссылке https://medium.com/@anoop.goudar/how-to-get-data-from-blob-url-to-node-js-server-using-selenium-88b1ad57e36d

person AnoopGoudar    schedule 07.04.2018