如何使用Selenium(任何版本)下载图像?
我想知道,如何使用selenium/webdriver下载页面的图像。假设需要用户会话来下载图像,因此使用纯URL是没有帮助的。非常感谢任何示例代码。我更喜欢这样做:如何使用Selenium(任何版本)下载图像?,selenium,webdriver,Selenium,Webdriver,我想知道,如何使用selenium/webdriver下载页面的图像。假设需要用户会话来下载图像,因此使用纯URL是没有帮助的。非常感谢任何示例代码。我更喜欢这样做: 1. Get the SRC attribute of the image. 2. Use ImageIO.read to read the image onto a BufferedImage 3. Save the BufferedImage using ImageIO.write function 例如 String sr
1. Get the SRC attribute of the image.
2. Use ImageIO.read to read the image onto a BufferedImage
3. Save the BufferedImage using ImageIO.write function
例如
String src=imgElement.getAttribute('src');
buffereImage buffereImage=ImageIO.read(新URL(src));
File outputfile=新文件(“saved.png”);
write(bufferedImage,“png”,outputfile);
如果需要测试该映像是否可用并存在,可以执行以下操作:
protected boolean isResourceAvailableByUrl(String resourceUrl) {
// backup current url, to come back to it in future
String currentUrl = webDriver.getCurrentUrl();
try {
// try to get image by url
webDriver.get(resourceUrl);
// if "resource not found" message was not appeared - image exists
return webDriver.findElements(RESOURCE_NOT_FOUND).isEmpty();
} finally {
// back to page
webDriver.get(currentUrl);
}
}
WebElement logo = driver.findElement(By.cssSelector(".image-logo"));
String logoSRC = logo.getAttribute("src");
URL imageURL = new URL(logoSRC);
BufferedImage saveImage = ImageIO.read(imageURL);
ImageIO.write(saveImage, "png", new File("logo-image.png"));
但您需要确定的是,在执行此方法之前,通过currentUrl确实会使您返回页面。我的情况就是这样。如果没有-您可以尝试使用:
webDriver.navigate().back()
而且,不幸的是,似乎没有机会分析响应状态代码。这就是为什么您需要在未找到的页面上找到任何特定的web元素,并检查它是否出现,然后确定该图像不存在
这只是权宜之计,因为我没有找到任何正式的方法来解决它
注:
当您使用授权会话获取资源时,此解决方案非常有用,并且不能仅通过ImageIO或严格地通过HttpClient下载资源。另一个最正确的解决方案是通过简单的HTTP请求直接下载资源。
您可以使用webDriver的用户会话,因为它存储cookies。
在我的示例中,我只是分析它返回的状态代码。若为200,则图像存在,可供显示或下载。若您真的需要下载文件本身,那个么您可以从httpResponse实体(将其用作简单的输入流)获取所有图像数据
这里的其他解决方案不适用于所有浏览器,也不适用于所有网站,或者两者都适用 这个解决方案应该更加稳健。它使用浏览器查看图像,调整浏览器大小以适应图像大小,拍摄屏幕截图,最后将浏览器大小调整回原始大小 蟒蛇: 此解决方案的一个缺点是,如果图像非常小,浏览器将不会调整到那么小的大小,并且可能会在其周围出现黑色边框。我更喜欢这样:
protected boolean isResourceAvailableByUrl(String resourceUrl) {
// backup current url, to come back to it in future
String currentUrl = webDriver.getCurrentUrl();
try {
// try to get image by url
webDriver.get(resourceUrl);
// if "resource not found" message was not appeared - image exists
return webDriver.findElements(RESOURCE_NOT_FOUND).isEmpty();
} finally {
// back to page
webDriver.get(currentUrl);
}
}
WebElement logo = driver.findElement(By.cssSelector(".image-logo"));
String logoSRC = logo.getAttribute("src");
URL imageURL = new URL(logoSRC);
BufferedImage saveImage = ImageIO.read(imageURL);
ImageIO.write(saveImage, "png", new File("logo-image.png"));
使用selenium获取图像src
elemImg.get_attribute('src')
为此使用编程语言,对于python;
检查以下答案:
这里是一个javascript解决方案。 这有点傻——而且我厌倦了用太多的请求来攻击源映像的服务器。有人能告诉我fetch()是否访问浏览器的缓存吗?我不想向源服务器发送垃圾邮件 它在窗口中附加一个FileReader(),获取图像并将其转换为base64,并将字符串标记到窗口中 然后,驱动程序可以返回该窗口变量
export async function scrapePic(driver) {
try {
console.log("waiting for that profile piccah")
console.log(driver)
let rootEl = await driver.findElement(By.css('.your-root-element'));
let imgEl = await rootEl.findElement(By.css('img'))
await driver.wait(until.elementIsVisible(imgEl, 10000));
console.log('profile piccah found')
let img = await imgEl.getAttribute('src')
//attach reader to driver window
await driver.executeScript(`window.myFileReader = new FileReader();`)
await driver.executeScript(`
window.myFileReader.onloadend = function() {
window['profileImage'] = this.result
}
fetch( arguments[0] ).then( res => res.blob() ).then( blob => window.electronFileReader.readAsDataURL(blob) )
`, img)
await driver.sleep(5000)
let img64 = await driver.executeScript(`return window.profileImage`)
console.log(img64)
} catch (e) {
console.log(e)
} finally {
return img64
}
}
为我工作:
# open the image in a new tab
driver.execute_script('''window.open("''' + wanted_url + '''","_blank");''')
sleep(2)
driver.switch_to.window(driver.window_handles[1])
sleep(2)
# make screenshot
driver.save_screenshot("C://Folder/" + photo_name + ".jpeg")
sleep(2)
# close the new tab
driver.execute_script('''window.close();''')
sleep(2)
#back to original tab
driver.switch_to.window(driver.window_handles[0])
对于我的用例,存在cookies和其他问题,使得这里的其他方法不适合 最后,我使用XMLHttpRequest填充了一个文件读取器(来自,然后使用Selenium的
ExecuteAsyncScript
(如中所示)调用该读取器)。这使我能够得到一个直接解析的文件
下面是我获取数据URL的C#代码:
公共字符串ImageUrlToDataUrl(IWebDriver驱动程序,字符串imageUrl)
{
var js=新的StringBuilder();
js.AppendLine(“var done=arguments[0];”;//来自ExecuteAsyncScript的回调
js.AppendLine(@)
函数toDataURL(url,回调){
var xhr=new XMLHttpRequest();
xhr.onload=函数(){
var reader=new FileReader();
reader.onloadend=函数(){
回调(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET',url);
xhr.responseType='blob';
xhr.send();
}“”;//XMLHttpRequest->FileReader->DataURL转换
js.AppendLine(“toDataURL(“+imageUrl+”,done);”;//调用函数
var executor=(IJavaScriptExecutor)驱动程序;
var dataUrl=executor.ExecuteAsyncScript(js.ToString())作为字符串;
返回dataUrl;
}
尝试以下操作
JavascriptExecutor js = (JavascriptExecutor) driver;
String base64string = (String) js.executeScript("var c = document.createElement('canvas');"
+ " var ctx = c.getContext('2d');"
+ "var img = document.getElementsByTagName('img')[0];"
+ "c.height=img.naturalHeight;"
+ "c.width=img.naturalWidth;"
+ "ctx.drawImage(img, 0, 0,img.naturalWidth, img.naturalHeight);"
+ "var base64String = c.toDataURL();"
+ "return base64String;");
String[] base64Array = base64string.split(",");
String base64 = base64Array[base64Array.length - 1];
byte[] data = Base64.decode(base64);
ByteArrayInputStream memstream = new ByteArrayInputStream(data);
BufferedImage saveImage = ImageIO.read(memstream);
ImageIO.write(saveImage, "png", new File("path"));
我发现避免两次下载图像的唯一方法是使用ChromeDevTools协议查看器 在Python中,这将提供:
import base64
import pychrome
def save_image(file_content, file_name):
try:
file_content=base64.b64decode(file_content)
with open("C:\\Crawler\\temp\\" + file_name,"wb") as f:
f.write(file_content)
except Exception as e:
print(str(e))
def response_received(requestId, loaderId, timestamp, type, response, frameId):
if type == 'Image':
url = response.get('url')
print(f"Image loaded: {url}")
response_body = tab.Network.getResponseBody(requestId=requestId)
file_name = url.split('/')[-1].split('?')[0]
if file_name:
save_image(response_body['body'], file_name)
tab.Network.responseReceived = response_received
# start the tab
tab.start()
# call method
tab.Network.enable()
# get request to target the site selenium
driver.get("https://www.realtor.com/ads/forsale/TMAI112283AAAA")
# wait for loading
tab.wait(50)
虽然@aboy021 JS代码语法正确,但我无法运行该代码。(使用ChromeV83.xx) 但是,这段代码有效(Java):
如何下载到文件,从元素文本或属性获取URL
using OpenQA.Selenium.Extensions;
...
var driver = new ChromeDriver();
// from element attribute
var element = driver.FindElement(By.XPath("//img[@id='my_img']")).DownloadResource(path: @"C:\images\cap_image_01.png", attribute: "src");
// from element text
var element = driver.FindElement(By.XPath("//div[1]")).DownloadResource(path: @"C:\images\cap_image_01.png");
using Extensions;
...
var driver = new ChromeDriver();
// from element attribute
var element = driver.FindElement(By.XPath("//img[@id='my_img']")).DownloadResource(path: @"C:\images\cap_image_01.png", attribute: "src");
// from element text
var element = driver.FindElement(By.XPath("//div[1]")).DownloadResource(path: @"C:\images\cap_image_01.png");
完整的扩展代码可在此处找到:
如果您想在不编写代码的情况下使用此方法,请使用NuGet
用法
using OpenQA.Selenium.Extensions;
...
var driver = new ChromeDriver();
// from element attribute
var element = driver.FindElement(By.XPath("//img[@id='my_img']")).DownloadResource(path: @"C:\images\cap_image_01.png", attribute: "src");
// from element text
var element = driver.FindElement(By.XPath("//div[1]")).DownloadResource(path: @"C:\images\cap_image_01.png");
using Extensions;
...
var driver = new ChromeDriver();
// from element attribute
var element = driver.FindElement(By.XPath("//img[@id='my_img']")).DownloadResource(path: @"C:\images\cap_image_01.png", attribute: "src");
// from element text
var element = driver.FindElement(By.XPath("//div[1]")).DownloadResource(path: @"C:\images\cap_image_01.png");
建议使用NuGet,因为它包含更多的Selenium工具和扩展
无需NuGet即可使用(自行实现)
扩展类
using System.IO;
using System.Net.Http;
using System.Text.RegularExpressions;
namespace Extensions
{
public static class WebElementExtensions
{
public static IWebElement DownloadResource(this IWebElement element, string path)
{
return DoDownloadResource(element, path, "");
}
public static IWebElement DownloadResource(this IWebElement element, string path, string attribute)
{
return DoDownloadResource(element, path, attribute);
}
private static IWebElement DoDownloadResource(this IWebElement element, string path, string attribute)
{
// get resource address
var resource = (string.IsNullOrEmpty(attribute))
? element.Text
: element.GetAttribute(attribute);
// download resource
using (var client = new HttpClient())
{
// get response for the current resource
var httpResponseMessage = client.GetAsync(resource).GetAwaiter().GetResult();
// exit condition
if (!httpResponseMessage.IsSuccessStatusCode) return element;
// create directories path
Directory.CreateDirectory(path);
// get absolute file name
var fileName = Regex.Match(resource, @"[^/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))").Value;
path = (path.LastIndexOf(@"\") == path.Length - 1)
? path + fileName
: path + $@"\{fileName}";
// write the file
File.WriteAllBytes(path, httpResponseMessage.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult());
}
// keep the fluent
return element;
}
}
}
用法
using OpenQA.Selenium.Extensions;
...
var driver = new ChromeDriver();
// from element attribute
var element = driver.FindElement(By.XPath("//img[@id='my_img']")).DownloadResource(path: @"C:\images\cap_image_01.png", attribute: "src");
// from element text
var element = driver.FindElement(By.XPath("//div[1]")).DownloadResource(path: @"C:\images\cap_image_01.png");
using Extensions;
...
var driver = new ChromeDriver();
// from element attribute
var element = driver.FindElement(By.XPath("//img[@id='my_img']")).DownloadResource(path: @"C:\images\cap_image_01.png", attribute: "src");
// from element text
var element = driver.FindElement(By.XPath("//div[1]")).DownloadResource(path: @"C:\images\cap_image_01.png");
页面上显示的实际图像。而不是页面的整个屏幕截图。请看,窗口已经在页面上加载了配置文件pic,我希望在它执行fetch()时,它只是进入缓存…我不完全确定如何确认是否是这种情况。新选项卡是否会向源代码发出新请求?我想是的,但没有与Snifferi检查。如果不想双重下载图像,请禁用chrome中的图像:prefs={“profile.managed_default_content_settings.images”:2}chrome_options.add_option(“prefs”,prefs)有趣的想法,但这不会提供原始图像这是一个宝石!伟大的发现!旁注:当然你会以这种方式释放原始照片的所有EXIF/元数据。最好的解决方案。花了我很多时间。希望有一天能好好利用它。:)也许有人能告诉我为什么aboy021版本不适合我。