Napisanie "Bota" wykonującego proste czynności na stronie internetowej.

0

Witam wszystkim bardzo serdecznie.

Co oznacza podany wyżej temat? Mianowicie, od niedawna pracuję w pewnej firmie logistycznej w dziale administracji. Głównie jest to żmudna robota papierkowo-excelowa na nieco przestarzałych i wolnych systemach. W firmie raczej nie ma nikogo kto się zajmuje biegle ogarnianiem naszego IT (prawdopodobnie robi to zewnętrzna firma) i przez to wiele zadań w firmie musimy wykonywać ręcznie.

Jedną z tych procedur jest zamykanie tzw. "small claimów". Chodzi z grubsza o to że gdy zaopatrujemy sklep to klient nie otrzymawszy jakiegoś towaru (np. 2 kartony mleka za mało) zgłasza to do naszego systemu. Musi jednocześnie w przeciągu jakiegoś tam czasu udowodnić nam to że ten towar faktycznie do niego nie przyjechał. Jak wiadomo z takimi ilościami różnie to bywa. Jedni to zgłoszą i udowodnią, ale nikomu z biura się tego nie będzie chciało zdejmować z systemu. Inni klienci to zgłaszają ale nie udowadniają, stąd też zgłoszenie dalej wisi. Generalnie zbiera się tego ogromna ilość i nikt jeszcze nie pofatygował się aby to zautomatyzować.

Tak się jakoś składa że chyba jako jeden z niewielu mam nieco większe pojęcie o pracy z większymi ilościami informacji. Część osób dziwiła się gdy pokazywałem im proste makra w excelu czy kwerendy wyszukujące w Accessie :D

Do sedna, cała procedura zamykania tych zgłoszeń jest banalnie prosta i opisana przeze mnie w dokumencie w drugim poście (to mój pierwszy post stąd nie mogę wklejać linków :( )
Jakieś tam pojęcie na temat programowania mam. Głównym koniem pociągowym są dla mnie podstawy C++ i to tyle :D Nie wiem ogólnie nawet od czego zacząć. Wspomnieć mogę tylko tyle że do systemu wchodzimy poprzez wpisanie adresu w odnośniku przeglądarki bez logowania (loguje się z automatu z danych z Windowsa) i strona ta jest napisana jak się nie mylę w HTML'u.

Liczę na przynajmniej wskazówki o czym musiałbym zacząć czytać by coś takiego stworzyć i czy w ogóle jest to warte zachodu i realne dla takiego laika jak ja, liczę na waszą pomoc dając mi rady i wskazówki:) Jak podałem za mało informacji to jutro jestem w firmie i mogę podać więcej.
Systemu w którym robimy daną procedurę nie jestem w stanie udostępnić, bo raz i tak nie da się do niego wejść spoza firmy, dwa dane poufne i takie tam :)

0

Dokument opisujący procedurę zamykania claimów

docs.google.com/document/d/1ToY7kp_B4-paI9go8g99Z6OmPGK0FyuD7Puo1uwbyf8/edit?usp=sharing

1

Selenium automates browsers. That's it! What you do with that power is entirely up to you. Primarily, it is for automating web applications for testing purposes, but is certainly not limited to just that. Boring web-based administration tasks can (and should!) be automated as well.

Dobierz sobie język programowania jaki tam chciałbyś, bodajże te są dostępne: Java C# Ruby Pythong NodeJS i dobrej zabawy :D

Jak na moje, to jedynie obawiam się tego okienka z "OK" do kliknięcia, a reszta wydaje się do zrobienia.

Problem z zleceniem tego komuś jest pewnie taki, że nie możesz dać dostępu do tego panelu komuś(firmowe dane?), a jeżeli nie znasz htmla, to będzie to trochę zabawy :P

Tak personalnie, to starałbym się pominąć Excela - ty po prostu byś te najważniejsze dane do jakiegoś pliku, o jakiejś tam strukturze wrzucał i tyle.

0

Dużo prościej i wydajniej jest użyć http requestów.

0

Dzieki panowie za odzew i chec pomocy :D

[WeiXiao napisał(a)]:

Problem z zleceniem tego komuś jest pewnie taki, że nie możesz dać dostępu do tego panelu komuś(firmowe dane?), a jeżeli nie znasz htmla, to będzie to trochę zabawy :P

No niestety, ale nie udostepnie tego panelu raz ze wzgledu na dane, a dwa ze przeciez nie chce wkladac w to kasy z wlasnej kieszeni. Jedyne co jestem w stanie zrobic to po prostu zapisac te strony i wrzucic je gdzie tak zeby mozna bylo obejrzec kod i stronke offline.

[Sunnyline2 napisał(a)]:

Dużo prościej i wydajniej jest użyć http requestów.

A zechcialbys moze podeslac stronke gdzie zaczac szukac informacji? W Googlu wyskakuje wiele pozycji, ale nie wiem na ktorej znajde najbardziej przydatne informacje

0

Zależy w jakim języku programowania chciałbyś to wykonać, polecam C# lub Jave a na upartego python.
Jeśli C# to wybrałbym taki zestaw https://www.dotnetperls.com/httpclient + parser https://github.com/AngleSharp/AngleSharp

0

Super, wielkie dzieki ! :) Chyba zdecyduje sie na C# ze wzgledu na wczesniejsza stycznosc z C++.
Powiesz mi tylko jakbys jeszcze mogl czy moj plan ktory zakladam wypali? Chce zeby to byla aplikacja konsolowa ktora na wejsciu pobierze z pliku tekstowego w ktorym odseparowane tabulatorem beda kolejno: numer zgloszenia oraz powod ktore umieszczam w stringu, po czym odwoluje program do funkcji o nazwie np "zamknij" ktora laczy sie z adresem i wykonuje na niej szereg tych instrukcji ktore opisalem w dokumencie? Calosc zapetlam az do konca pliku textowego

Kurde ale juz nie moge sie doczekac az wroce do domu i sie z tym pobawie :D

0
Freezu napisał(a):

Super, wielkie dzieki ! :) Chyba zdecyduje sie na C# ze wzgledu na wczesniejsza stycznosc z C++.

C# z C++ ma niewiele wspólnego - C# dużo prostszy i szybciej możesz coś napisać.

Powiesz mi tylko jakbys jeszcze mogl czy moj plan ktory zakladam wypali? Chce zeby to byla aplikacja konsolowa ktora na wejsciu pobierze z pliku tekstowego w ktorym odseparowane >tabulatorem beda kolejno: numer zgloszenia oraz powod ktore umieszczam w stringu, po czym odwoluje program do funkcji o nazwie np "zamknij" ktora laczy sie z adresem i wykonuje na niej >szereg tych instrukcji ktore opisalem w dokumencie? Calosc zapetlam az do konca pliku textowego

A czemu by nie?

0
[Sunnyline2 napisał(a)]:

C# z C++ ma niewiele wspólnego - C# dużo prostszy i szybciej możesz coś napisać.

No dobra, to dzis wieczor siadam do tego, dzieki za rady :)

W razie pytan bede pisal

0
Freezu napisał(a):
[Sunnyline2 napisał(a)]:

Zależy w jakim języku programowania chciałbyś to wykonać, polecam C# lub Jave a na upartego python.
Jeśli C# to wybrałbym taki zestaw dotnetperls.com/httpclient + parser github.com/AngleSharp/AngleSharp

Super, wielkie dzieki ! :) Chyba zdecyduje sie na C# ze wzgledu na wczesniejsza stycznosc z C++.
Powiesz mi tylko jakbys jeszcze mogl czy moj plan ktory zakladam wypali? Chce zeby to byla aplikacja konsolowa ktora na wejsciu pobierze z pliku tekstowego w ktorym odseparowane tabulatorem beda kolejno: numer zgloszenia oraz powod ktore umieszczam w stringu, po czym odwoluje program do funkcji o nazwie np "zamknij" ktora laczy sie z adresem i wykonuje na niej szereg tych instrukcji ktore opisalem w dokumencie? Calosc zapetlam az do konca pliku textowego

Kurde ale juz nie moge sie doczekac az wroce do domu i sie z tym pobawie :D

Ja to poszedłbym w tym kierunku:

Zrób sobie klasę, która będzie trzymać te dane.

Do czytania z pliku możesz użyć np File.ReadAllLines (C#)

https://msdn.microsoft.com/pl-pl/library/system.io.file.readalllines(v=vs.110).aspx

Później na każdej linijce zrobisz Split('znaczek którym rozdzielasz dane') i zrobisz instancje klasy, którą wypełnisz tymi danymi i dodasz ją do jakiejś kolekcji tych wszystkich obiektów z danymi.

Za "znaczek" podstawiasz np ten znak tabulacji lub przecinek, lub cokolwiek tam chcesz.

A następnie na każdym elemencie tej kolekcji z danymi wykonasz kod, który zrobi Ci to na tej stronce

Ta sama funkcja na dwa sposoby (bo zaraz ktoś by napisał ee przecie można było linq!! :D):

public static List<Dane> processDataFromFile(string path)
{
    var ListOfDane = new List<Dane>();

    foreach (var line in File.ReadAllLines(path))
    {
        var splittedData = line.Split(',');

        ListOfDane.Add
        (
            new Dane
            {
                nr_zgloszenia = Convert.ToInt32(splittedData[0].Trim()),
                powod = splittedData[1].Trim()
            }
        );
    }
    return ListOfDane;
}
public static List<Dane> processDataFromFileLinQ(string path)
{
    return File
            .ReadAllLines(path)
            .ToList()
            .Select
            (
                x => new Dane
                {
                    nr_zgloszenia = Convert.ToInt32(x.Split(',')[0].Trim()),
                    powod = x.Split(',')[1].Trim()
                }
            ).ToList();               
}
public class Dane
{
    public int nr_zgloszenia { get; set; }
    public string powod { get; set; }
}

Sprawdzane na danych

1,bo tak
2,bo nie
0

Witam was ponownie, otoz, odkrylem pewien lopatologiczny sposob na to by nieco zautomatyzowac caly proces. Poszedlem calkowicie inna droga i nie wiem w ogole czy ma to jakis sens :D Generalnie skrypt "prawie" dziala. Ogolnie zrobilem tak ze zaczalem korzystac z konsoli google chrome. Po prostu wyszukiwalem elementy strony i wykonywalem na nich proste operacje (value="XXX" albo .click()). Kod wyglada w taki sposob jak ponizej, aczkolwiek kazdy z tych krokow musze wpisywac ponownie po tym jak strona wysle mi odpowiedz po jakiejs czynnosci. Przykladowo za pomoca kodu wpisze w pole wyszukiwania numer zamowienia i klikne szukaj i wtedy moj skrypt sie przerywa i musze mu wydac kolejna komende :( Nie da sie zrobic tak zeby skrypt dzialal nie zaleznie od strony?
Kod

//1 - wklepanie w pole tekstowe numeru zamowienia oraz wyszukanie (pozniej nalezy dodac funkcje pobierania numeru zamowienia np z listy lub tablicy)

Content_OrderNumberTextBox.value="472472833";
Content_OrderNumberButton.click();

//2 - tu przenosimy sie do okienka z wynikami wyszukiwania, musze teraz kliknac w lacze do zamowienia ktore chce zamkanac

Content_IncidentGridView_OrderNumberHyperLink_0.click()

//3 - tu nastepuje update jedynie wiersza nr 7 w ktorym wiem doskonale ze nalezy dokonac operacji, potrzebuje tu natomiast petli for ktora bedzie wykonywac sprawdzanie i ewentualne operacje no i po kazdym sprawdzeniu podnosic numer wiersza az do konca spisu

if (Content_ClaimDiscrepancyGridView_ClaimReasonsDropDownList_7.value=50) // sprawdzam czy trzeba w ogole cokolwiek edytowac
{
Content_ClaimDiscrepancyGridView_StockAdminNotesTextBox_7.value = "NSA made, no returns received, no LIW/FIW reported. 17.07.18";
Content_ClaimDiscrepancyGridView_ClaimSubReasonDropDownList_7.value = 91; 
Content_ClaimDiscrepancyGridView_StatusDropDownList_7.value=2;
}
Content_UpdateButton.click(); // gdy juz pozamykam wszystkie wiersze do zamkniecia, zamowienie aktualizuje tym przyciskiem

// tu wyskakuje okienko z OK i na ten moment musze to potwierdzac enterem :(

//4 - powrot do panelu wyszukiwania

Content_backButton.click();

Mysle ze jest to sposob troche przekombinowany, ale gdyby tak numeru zamowien pobieralo z listy i operacja wykonywala sie az do konca tych zamowien to mogloby to dzialac :D

Dajcie znac co myslicie

0

Do klikania po stronie i wprowadzania tekstu do inputów wystarczy dodatek do przeglądarki. - iMacros.

0

A skupmy sie na chwile na samym procesie zamykania zgloszen. W tym przypadku ponizszy kod oznacza:

if (Content_ClaimDiscrepancyGridView_ClaimReasonsDropDownList_X.value=50) // jezeli "Claim Reason" w wierszu X rowna sie opcji nr 50 czyli "short disputed" wtedy
{
Content_ClaimDiscrepancyGridView_StockAdminNotesTextBox_X.value = "NSA made, no returns received, no LIW/FIW reported. 17.07.18"; // w polu textowym wpisz wiadomosc w cudzyslowiu
Content_ClaimDiscrepancyGridView_ClaimSubReasonDropDownList_X.value = 91; // z rozwijanej listy wybierz opcje nr 91
Content_ClaimDiscrepancyGridView_StatusDropDownList_X.value=2; // z rozwijanej listy wybierz opcje nr 2
}

Chcialbym ten kod zamknac w petli ktora w miejscu X podstawi iterator zaczynajac od zera i np konczac na 50 (albo na ostatnim wierszu jezeli sie uda). Nie jest to takie banalne bo gdy ustawie utworze zmienna X i probuje wykonwac funkcje "Content_ClaimDiscrepancyGridView_StatusDropDownList_X.value=2" wtedy nie widzi tam zmiennej tylko tak jakby czyta jako cale ID

Nie wiem czy dobrze to w ogole tlumacze xd

0

Ogarnij sobie cos takiego jak UiPath. Prosty program do robienia robotow. Na Twoj uzytek bedzie wystarczajaca podstawowa werjsa bez Orchestratora i bys sobie swoj flow odpalal recznie.

0
Sunnyline2 napisał(a):

Zależy w jakim języku programowania chciałbyś to wykonać, polecam C# lub Jave a na upartego python.
Jeśli C# to wybrałbym taki zestaw https://www.dotnetperls.com/httpclient + parser https://github.com/AngleSharp/AngleSharp

RestSharp jest o wiele bardziej przyjemny.

Do autora: często pisałem sobie różne boty do internetowych gier komputerowych, które automatyzowały pracę.
Możesz użyć np. Selenium. Nagrasz makro, które potem będziesz otwarzał. Możesz również podać jakieś argumenty, by makro klikało odpowiednie elementy.

Znacznie wydajniej i trudniej jest użyć samych requestów. Pobierz Telerik Fiddler i podejrzyj jakie dane używasz do akcji na stronie. Podejrzewam, że nie będzie to jakoś bardzo trudne, bo strona wygląda na dość starą. Pewnie do zalogowania się potrzebne jest wysłanie jednego posta z loginem i hasłem itd. Użyj do tego wspomnianego RestSharp. Jest bardzo prosty w użyciu.

Możesz zrobić coś w tym stylu:

class Account
{
	public string Email {get; private set;}
	public string Password {get; private set;}
	public bool Logged {get; private set;)
	
	public Account(string email, string password)
	{
		this.Email = email;
		this.Password = password;
	}
}

static class ClaimUrls
{
	public staitc string BaseUrl = "http://www.mojastrona.pl";
	public static string Index = "/Index";
	public static string Login = "/Login";
	public static string RemoveClaim = "/Delete";
	public static string UpdateClaim = "/Update";
}

class LoginDTO
{
	public string Email {get; set;}
	public string Password {get; set;}
}

enum Status
{
	Open = 0,
	Closed = 1,
}

class ChangeClaimMessageDTO
{
	public int ClaimId {get; set;}
	public string SubReason {get; set;}
	public Status Status {get; set;}
	public string StockAdminNotes {get; set;}
}

class ClaimDataProvider
{
	public LoginDTO GetLoginContent(string login, string password)
	{
		return new LoginDTO
		{
			Email = login,
			Password = password
		};
	}
	
	public ChangeClaimMessageDTO GetChangeClaimMessageContent(int claimId, string subReason, Status status, string stockAdminNotes)
	{
		return new ChangeClaimMessageDTO
		{
			ClaimId = claimId,
			SubReason = subReason,
			Status = status,
			StockAdminNotes = stockAdminNotes
		};
	}
}

class RequestManager
{
	private RestClient client;
	
	public RequestManager()
	{
		client = new RestClient(RaportUrls.BaseUrl);
		client.CookieContainer = new CookieContainer();
	}
	
	public IRestResponse ExecuteRequest(string path, object content, Methot method = Method.POST)
	{
		var request = new RestRequest(path, method);
		request.AddJsonBody(content);
		var response = client.ExecuteRequest(request);
		return response;
	}
}

class ClaimManager
{
	
	private Account account;
	private ClaimDataProvider dataProvider;
	private RequestManager requestManager;
	
	public ClaimManager()
	{
		requestManager = new RequestManager();
		account = new Account(email, password);
		dataProvider = new ClaimDataProvider();
	}
	
	public void Login()
	{
		if (account == null)
			throw new ArgumentNullException("Account is not set");
			
		var content = dataProvider.GetLoginContent(account.Email, account.Password);
		var response = requestManager.ExecuteRequest(ClaimUrls.Login, content, Method.POST);	
	}
	
	public void ChangeClaimMessage(int claimId, string subReason, Status status, string stockAdminNotes)
	{
		var content = dataProvider.GetChangeClaimMessageContent(claimId, subReason, status, stockAdminNotes);
		var response = requestManager.ExecuteRequest(ClaimUrls.Update, content, Method.POST);
	}
}

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