Obróbka obrazka (selenium chrome driver)

0

Cześć,

mam takie zadanie ściągnięcia obrazka z Internetu sprawdzenie jego atrybutów (szerokość , wysokość itp)
zapisać go do bazy (nie zapisane jak chyba w postaci binarnej) i później wyświetlenie tego obrazka na stronie www.

już wcześniej miałem do czynienia z biblioteką selenium i wykorzystując właśnie ją umiem odwołać się do obrazka na stronie, ale nie umiem go zapisać do bazy odczytać jego parametrów i wgrać do bazy.
mój aktualny kod wygląda tak

        private void button1_Click(object sender, EventArgs e)
        {
            ChromeOptions options = new ChromeOptions();
            options.AddArgument("ignore-certificate-errors");
            options.AddArgument("start-maximized");
            options.AddArgument("disable-popup-blocking");
            IWebDriver driver = new ChromeDriver(options);

            driver.Navigate().GoToUrl("link do obrazka");
            var img = driver.FindElement(By.XPath("/html/body/div[8]/main/div[6]/")); // <- jakiś testowy XPath

        }

miałby ktoś jakiś pomysł ?

0

Pobranie obrazka jest bardzo proste, otwierasz link i zapisujesz strumień bajtów do pliku, który ci serwer poda.

Z poziomu selenium możesz pobrać parametry img width, height, ale te określają wymiary obrazu na stronie.
A parsując plik w nagłówkach masz wymiary, ale każdy format ma własne headery, ręcznie nie ma co tego parsować bo za dużo.

W pythonie biblioteka PIL chyba obsługuje dużą liczbę formatów takich jak jpg, bmp.

Możesz na szybko sam klepnąć przejście po headerach bo to zwykłe bajty, np. na offsecie 20 bajta następne 2 bajty określają wysokość i na offsecie innym tam szerokość.

Ale może jakieś narzędzia są w c#, które ci dadzą jednolity interface do każdego rodzaju pliku.

0

Unikałbym tutaj Selenium

Tu masz przykład jak pobrać i zapisać obrazek ze strony.

Jeżeli nie masz urla, to i tak według mnie lepiej byłoby pobrać HTML strony i z niej wyciągnąć link (no chyba, że to aplikacja SPA, to chyba pozostaje Selenium)

RestClient restClient = new RestClient(@"https://4programmers.net/");

var resultFileName = Path.ChangeExtension(Guid.NewGuid().ToString(), "jpg");
var fileBytes = restClient.DownloadData(new RestRequest("uploads/photo/580e4bc862106.jpg", Method.GET));
File.WriteAllBytes(resultFileName, fileBytes);
0

A dlaczego unikać Selenium?
na razie mój kod wygląda tak

private void button1_Click(object sender, EventArgs e)
        {
            ChromeOptions options = new ChromeOptions();
            options.AddArgument("ignore-certificate-errors");
            options.AddArgument("start-maximized");
            options.AddArgument("disable-popup-blocking");
            IWebDriver driver = new ChromeDriver(options);

            driver.Navigate().GoToUrl("http://anonco.pl/ikona-swieta-bombka-pilka-nozna-christmas-icon-bauble-football/");
            var img = driver.FindElement(By.XPath("/html/body/div[1]/div/div/div/article/div/p[1]/img"));

            lab_url.Text = img.GetAttribute("src").ToString();
            lab_width.Text = img.GetAttribute("width").ToString();
            int width = int.Parse(lab_width.Text);
            lab_height.Text = img.GetAttribute("height").ToString();
            int height = int.Parse(lab_height.Text);

            driver.Quit();

            SaveToDataBase(img.GetAttribute("src").ToString(), width, height, "data");

        }
        public void SaveToDataBase(string url, int width, int height, string data)
        {
            try
            {
                string MyConnection2 = "datasource=localhost;port=3306;username=user;password=Passw0rd;database=images";
                string Query = "insert into images( url, width, height, data) values('"+url+"',"+width+","+height+",'data');";
                MySqlConnection MyConn2 = new MySqlConnection(MyConnection2);
                MySqlCommand MyCommand2 = new MySqlCommand(Query, MyConn2);
                MySqlDataReader MyReader2;
                MyConn2.Open();
                MyReader2 = MyCommand2.ExecuteReader();   
                MessageBox.Show("Save Data");
                while (MyReader2.Read())
                {
                }
                MyConn2.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

ale dalej nie wiem jak ogarnąć zapis pliku do bazy w postaci bajtów?

0

co do rozwiązania @WeiXiao to ja muszę zrobić to bardziej uniwersalnie, czyli nie wiem jaki to jest plik i np. odczytuję go z XPath dlatego używam Selenium.

0

@KiK:

A dlaczego unikać Selenium?

bo znacznie szybciej jest strzelić HTTP Geta, przeparsować HTML i pobrać co chcesz

niż odpalić przeglądarkę, przeklikać itd.

Generalnie jeżeli byś robił niewiele "zadań" za pomocą Selenium, to może by to przeszło, ale im więcej i im bardziej skomplikowane tym utrzymanie tego robi się problematyczne

ale dalej nie wiem jak ogarnąć zapis pliku do bazy w postaci bajtów?

Musiałbyś sprawdzić w kontekście konkretnej bazy np. C# save bytes in MSSQL

A nie lepiej byłoby Ci pliki zapisać na dysku, a w bazie ścieżkę?

string MyConnection2 = "datasource=localhost;port=3306;username=user;password=Passw0rd;database=images";
string Query = "insert into images( url, width, height, data) values('"+url+"',"+width+","+height+",'data');";
MySqlConnection MyConn2 = new MySqlConnection(MyConnection2);
MySqlCommand MyCommand2 = new MySqlCommand(Query, MyConn2);
MySqlDataReader MyReader2;
MyConn2.Open();
MyReader2 = MyCommand2.ExecuteReader();   
MessageBox.Show("Save Data");
while (MyReader2.Read())
{
}
MyConn2.Close();

są o wiele ładniejsze sposoby na zapis do bazy, a w dodatku unikają sklejania SQLi typu ('"+url+"',"+width+","+height+",'data');

obczaj sobie Dappera, przykład:

using (var db = new SqlConnection(connString))
{
    string insertQuery = @"INSERT INTO [dbo].[Customer]
	([FirstName], [LastName], [State], [City], [IsActive], [CreatedOn])
	VALUES
	(@FirstName, @LastName, @State, @City, @IsActive, @CreatedOn)";

    var result = db.Execute(insertQuery, new
    {
        customerModel.FirstName,
        customerModel.LastName,
        StateModel.State,
        CityModel.City,
        isActive,
        CreatedOn = DateTime.Now
    });
}
0

takie zapytanie parametryczne :) fajne
zdjęć nie mogę trzymać na dysku i dlatego muszę je trzymać w bazie

jeżeli chodzi o selenium to podoba mi się prostota tego rozwiązania. klikam w przeglądarce f12 wskazuję element, kompiuję XPath i ma hulać :)

0

aktualnie walczę z częścią kodu która ma mi pobrać plik z neta i wgrać na dysk i wydaje mi się że brakuje jakiegoś detalu ale otrzymuję błąd

public void ReadAndSaveImage()
        {
            IWebDriver driver = new ChromeDriver();
            driver.Navigate().GoToUrl("http://anonco.pl/ikona-swieta-bombka-pilka-nozna-christmas-icon-bauble-football/");

            IWebElement my_image = driver.FindElement(By.XPath("/html/body/div[1]/div/div/div/article/div/p[1]/img"));

            Point point = my_image.Location;
            int width = my_image.Size.Width;
            int height = my_image.Size.Height;

            Rectangle cropRect = new Rectangle();
            Bitmap src = Image.FromFile(my_image.GetAttribute("src")) as Bitmap;
            Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);

            using (Graphics g = Graphics.FromImage(target))
            {
                g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height),
                                 cropRect,
                                 GraphicsUnit.Pixel);
                target.Save(@"C:\img.png");
            }
        }

do Image.FromFile <- wrzucam ścieżkę do pliku w necie ale mi wywala błąd

0
var driver = new ChromeDriver();
driver.Navigate().GoToUrl("http://anonco.pl/ikona-swieta-bombka-pilka-nozna-christmas-icon-bauble-football/");

var img = driver.FindElement(By.XPath("/html/body/div[1]/div/div/div/article/div/p[1]/img"));
var src = img.GetAttribute("src");

using (var webClient = new WebClient())
{
    webClient.DownloadFile(src, @"c:\img.png");
}

Jak nie chcesz pobierać obrazka jeszcze raz, to możesz zakodować go do base64, a potem odkodować:

public static class Foo()
{
	static void Bar()
		{
			var driver = new ChromeDriver();
			driver.Navigate().GoToUrl("http://anonco.pl/ikona-swieta-bombka-pilka-nozna-christmas-icon-bauble-football/");
	
			var img = driver.FindElement(By.XPath("/html/body/div[1]/div/div/div/article/div/p[1]/img"));
			var bmp = driver.GetBitmap(img);
			bmp.Save(@"c:\aa\img.png");
		}
	}
}

public static class SeleniumExtensions
{
    public static Bitmap GetBitmap(this ChromeDriver driver, IWebElement element)
    {
        var base64 = driver.ExecuteScript(@"
            function getBase64Image(image) {
                if (image == null || image.nodeName.toLowerCase() !== 'img')
                    return '';

            	var canvas = document.createElement('canvas');
            	canvas.width = image.width;
            	canvas.height = image.height;
            	var ctx = canvas.getContext('2d');
            	ctx.drawImage(image, 0, 0);
            	var dataURL = canvas.toDataURL('image/png');
            	return dataURL.replace(/^data:image\/(png|jpg);base64,/, '');
            }
            
            return getBase64Image(arguments[0]);
        ", element).ToString();

        return BitmapHelper.Base64ToBitmap(base64);
    }
}

public static class BitmapHelper
{
    public static Bitmap Base64ToBitmap(string base64String)
    {
        var imageBytes = Convert.FromBase64String(base64String);
        using (var ms = new MemoryStream(imageBytes))
        {
            return Bitmap.FromStream(ms, true).ToBitmap();
        }
    }

    public static Bitmap ToBitmap(this Image image)
    {
        return new Bitmap(image);
    }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1