Page 1 of 3

Driving a Web Browser with PureBasic

Posted: Wed Oct 17, 2018 2:56 pm
by Kwai chang caine
Hello at all,

A day Normeus talk to me about Selenium in stand alone mode
It create a server and normally several langage can sending to him order in JSON
But all the langage in the list is OOP :|

Have you ever use it ?
Believe you it's possible to send simple order to him in PB ?
If by miracle yes :shock: , have you a simple example for open a google page for exampler 8)

Thanks in advance and have a good day :wink:

Re: Selenium in standalone mode

Posted: Mon Oct 22, 2018 2:33 pm
by Marc56us
I am also interested in this theme :)
I started a few days ago and managed to understand (I think) some elements.

1. In the simplest case, it is not necessary to use server, so Java (that's good, I hate this language :evil: )
One way is to control the browser through a WebDriver. This then acts as a proxy (so the browser concerned must be on the same machine)

For the moment I'm doing my tests in python, just install it and then install the module for Selenium (C:\> pip install selenium)
Then it is necessary to install the proxy (i.e: geckodriver.exe, chromedriver.exe) for the type of browser desired, in a directory accessible in the path.

It works well 8)

Because of HTTP, commands are sent as text to the proxy , So normally we should be able to do it with PB network commands :?:

But I can't find the list of orders, even here https://www.w3.org/TR/webdriver/ :(
:idea: So I just reuse the commands generated by Selenium IDE's macro recorder
https://www.seleniumhq.org/projects/ide/
(We can see what the Firefox proxy (GeckoDriver) receives by running geckodriver.exe -v
In python, all work (but slow))

:arrow: Like you, I would like to be able to do without an intermediate language and make PB "speak" directly to the proxy since these can be launched separately. :P
Logically SendNetworkString() and ReceiveNetworkData() should be enough :?:

I keep looking for this interesting subject... :wink:
:idea: It would be nice to be able to add PureBasic to the list of languages that can be used with Selenium
https://www.seleniumhq.org/download/#client-drivers

PS. Links for proxy:
FireFox WebDriver
https://github.com/mozilla/geckodriver/releases
geckodriver-v0.23.0-win64.zip

Chrome driver
https://sites.google.com/a/chromium.org ... /downloads
chromedriver_win32.zip

PS. There have been many versions of Selenium due to browser changes, making many Internet documentation obsolete or inaccurate.

Re: Selenium in standalone mode

Posted: Tue Oct 23, 2018 1:08 pm
by Kwai chang caine
Incrédible my friend, fortunately you are here....
i believe one moment i'm alone in the world to be interesting by this subject :cry:
And yet, more and more entreprise use this method or other for keep data on the web.
For compare prices, create database, robots, etc ..

Since several months, i try all what i found for remote FF, without real succès.
Try to create a pb proxy, sending data with pb server, using httprequest, adding mozrepl, xul, xpcom, sending js in adressbar by sendkey (works in part), sending js in progressbar with api Iaccessible (nobody can help me), i have also read it's surely possible for a good programmer to inject js directly in a dll of FF, wriiting with sendkeys a metbod for adding temporary addon (like this you can return data to pb with js), but also use scratchpad by sendkey,sendinput,after ruby with selenium, php withselenium, and like you python with selenium, i have even thinking to compile my own FF without all the stupids security protections (js locking in adressbar, addon permanent unsigned not allowed, etc...)
For the moment the only methods working is scratchpad and python.

But they are a long time already i try python and selenium.
Apparently it's the real professional method for remote browser.
And Normeus say to me why passing by python?
Sélénium works in standalone server, create an adress etc...
But you have right, no full example, and the explanation is in the minimum.
Everybody not be great programmer like i found on this PB forums :oops:
And i have nothing understand

I'm so happy you are also interesting to this subject
Today i'm not behind a pc, i answer you from my smartphone, but tomorrow yes, i read your answers and links another time,

I believe you and me surely married a day, (more simple for programming the same subject all the days) :lol: because it's not the first time we are on the same way :wink:

Have a real good day my french friend

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 10:55 am
by Kwai chang caine
Hello a new time MARC56 8)

I'm finally back !!! :mrgreen:

Image
My friend wrote:It works well 8)
Yes for one time, me too :shock:

With the two methods :

1/ Sending path of script (The most simple)

Code: Select all

 RunProgram(GetEnvironmentVariable("comspec"), "/c " + Python$ + " " + ScriptPy$, "", #PB_Program_Hide|#PB_Program_Open|#PB_Program_Read|#PB_Program_Error)
2/ Sending variable (Another "paire de manche" :mrgreen: )

Code: Select all

Script$ = "exec(|||\nfrom selenium import webdriver\n"
Script$ + "from selenium.webdriver.firefox.firefox_binary import FirefoxBinary\n"
Script$ + "binary = FirefoxBinary('F:\\\\A\\\\J\\\\C\\\\O\\\\Firefox61.0.2\\\\App\\\\Firefox\\\\firefox.exe')\n"
Script$ + "driver = webdriver.Firefox(firefox_binary=binary, executable_path=r'F:\\\\A\\\\B\\\\A\\\\B\\\\D\\\\B\\\\D\\\\B\\\\A\\\\PythonSelenium\\\\Python37\\\\geckodriver.exe')\n"
Script$ + "driver.get('https://www.youtube.com')\n|||)|"

RunProgram(GetEnvironmentVariable("comspec"), "/c " + Python$ + " -c " + ReplaceString(Script$, "|", Chr(34)), "", #PB_Program_Hide|#PB_Program_Open|#PB_Program_Read|#PB_Program_Error)
Fortunately, i have found this great site for help me 8), because,.... who ???? have say PYTHON is simple with his shit of space indentation :?
http://jagt.github.io/python-single-line-convert/
The proof is here, someone feeling forced to create a site, only for passing several lines to one, :lol:
I think FRED and his always big simplicity of meaning, have surely laughing like me when he see that,... the first time :shock: :lol: :lol:

Image

Code: Select all

I'm a part of line_
and also me_
me too 
We are far to the PB underscore :lol: :lol:
Marc56 wrote:that's good, I hate this language
Image

Welcome to the club !!!! :mrgreen:
Marc56 wrote:Because of HTTP, commands are sent as text to the proxy , So normally we should be able to do it with PB network commands
Are you sure ??? :shock:
Me... i believe, only OOP langage, and again not all, can talk to SELENIUM
''Le monsieur'' wrote:You will still need to use one of the WebDriver language bindings, which I'm not aware of any of the language bindings that are in C++, but perhaps one of the available languages could be used by your team for automation purposes.
https://stackoverflow.com/questions/173 ... ion-from-c
It's the reason why, even the powerfull C++ or C, not can talking to him :|
For the C i understand, .....he is not OOP, but the C++ :shock: not ask me why...surely something different between C++ and C#
Marc56 wrote:(We can see what the Firefox proxy (GeckoDriver) receives by running geckodriver.exe -v
In python, all work (but slow))
Interesting !!!! i don't know that !!! :shock:
My french friend wrote: It would be nice to be able to add PureBasic to the list of languages that can be used with Selenium
Ask to a blinded if he want to see 8)
I think we have much of chances to see that a day, that KCC become a real programmer after hundred years of learning !!! :mrgreen:

So thanks again for your kind answer 8) 8)
I beginned to me feel a little bit alone in this history :|
Image

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 12:29 pm
by Marc56us
Hi KCC,

You can "drive" webbrowser (chrome, Firefox) without Selenium and directly from PB without external language/script.
Look what CELTIC88 has done: http://forums.purebasic.com/english/vie ... 46#p516646
This shows that PureBasic can directly "talk" to the proxy (chromedriver, geckodriver) with network commands like SendNetworkString().

If you want to use Firefox instead of chrome, download FireFox WebDriver (geckodriver.exe)
https://github.com/mozilla/geckodriver/releases
uncompresse archive in your PB EXE or in a path dir (ie: %windir%)
Change driver and port

Code: Select all

; default_driver_Port = 9515
; driver_location$ = "chromedriver.exe"
default_driver_Port = 4444
driver_location$ = "geckodriver.exe"
:!: Chrome version work fine, but Gecko version hang ([ERROR] Invalid JSON value. (0)) :(

PS. Some good links
Webdriver reference
https://www.w3.org/TR/webdriver/
Et un lien intéressant qui explique le fonctionnement d'un Webdriver
https://makina-corpus.com/blog/metier/2 ... -parallele

:wink:

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 1:35 pm
by Kwai chang caine
Waooooouuuuuhhh !!!!! :shock:
I have "zapping" :mrgreen: completely this tips, and yet i have see it, when CELTIC write it :oops:
By force to read and try all this methods since all this months, i don't know where i am, i'm completely lost :|

Coooolll !!!! MARC !!! ............ you are more strong that the strong cheese !!!! 8)
Thanks a lot for your help..i love you 8)

Not use SELENIUM, it's a great step for KCCmanity :wink:

Image

PS: I love CELTIC too !!! :D

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 3:01 pm
by Kwai chang caine
Chrome version work fine, but Gecko version hang ([ERROR] Invalid JSON value. (0)) :(
The same issue :|

So i have thinking i have no FF installed
I always use portable version, so i asked myself, how the driver know the path of FF ?? :shock: surely they are a way for give it to him :idea:
And gods are with me today, i have found this link, with example of "Capabilities" (So not like me :mrgreen:)
https://firefox-source-docs.mozilla.org ... ities.html

So i have try to begin simple (Like me :mrgreen: )
And i know it's the begining of the start of the onset of the inception of our ROBOT :oops: ...but

Image

That open FF :shock:

Finish the
([ERROR] Invalid JSON value. (0)
Aurevoir, arrivederci, goodbye, Auf Wiedersehen

Image

Code: Select all

; http://forums.purebasic.com/english/viewtopic.php?p=516646&sid=5c05a993efbf6365ec8d55235e2c9751#p516646

Macro Req(Method,Loc,Cleng)

 Method + " "+Loc+" HTTP/1.1" + #CRLF$ +
          "Connection: Keep-Alive" + #CRLF$ +
          "Content-Type: application/json;charset=utf-8" + #CRLF$ +
          "Accept: */*" + #CRLF$ +
          "User-Agent: Mozilla/4.0" + #CRLF$ +
          "Content-Length: " + Cleng + #CRLF$ +
          #CRLF$

EndMacro

InitNetwork()

Procedure.s Webdriver_Req(ConnctionID ,url.s,sData.s,JsGetItem.s,JSONType = #PB_JSON_String,ReqType.s  = "POST")

 Protected pReq$ = Req(ReqType,url,StringByteLength(sData,#PB_Ascii)) + sData
 SendNetworkString(ConnctionID,pReq$,#PB_Ascii)
 Protected Size = 1024*1024*10
 Protected *pRepReq = AllocateMemory(Size)
 ReceiveNetworkData(ConnctionID,*pRepReq,Size)
 Protected RepReq.s = StringField(PeekS(*pRepReq,-1,#PB_Ascii),2,#CRLF$ + #CRLF$)
 FreeMemory(*pRepReq)
 Protected Jid = ParseJSON(#PB_Any, RepReq)
 ProcedureReturn RepReq
 
EndProcedure

default_driver_Port = 4444
driver_location$ = "geckodriver.exe"

Wbid = RunProgram(driver_location$ ,"" ,"",#PB_Program_Open)
Cid = OpenNetworkConnection("127.0.0.1", default_driver_Port)
; 
Url$ = "{"
Url$ +   "|capabilities|: {"
Url$ +         "|alwaysMatch|: {"
Url$ +             "|moz:firefoxOptions|: {"
;Url$ +                 "|binary|: |D:\\A\\J\\C\\O\\Firefox50.1.0\\App\\Firefox\\Firefox.exe|"
Url$ +                 "|binary|: |D:\\A\\J\\C\\O\\Firefox61.0.2\\App\\Firefox\\Firefox.exe|"
Url$ +             "}"
Url$ +         "}"
Url$ +     "}"
Url$ + "}"

Sid$ = Webdriver_Req(Cid, "/session", ReplaceString(Url$, "|", Chr(34)), "")
Debug Sid$

CloseNetworkConnection(Cid)

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 3:16 pm
by Kwai chang caine
Again better i have use the FF portable 62.0.3 and have this answer
{"value":{"sessionId":"51760df1-6346-4c1b-8692-f625314c001c","capabilities":{"acceptInsecureCerts":false,"browserName":"firefox","browserVersion":"62.0.3","moz:accessibilityChecks":false,"moz:geckodriverVersion":"0.22.0",
"moz:headless":false,"moz:processID":3920,"moz:profile":"C:\\Users\\Kcc\\AppData\\Local\\Temp\\rust_mozprofile.U9XqgpLDhHHd","moz:useNonSpecCompliantPointerOrigin":false,
"moz:webdriverClick":true,"pageLoadStrategy":"normal","platformName":"windows_nt","platformVersion":"6.1","rotatable":false,"timeouts":{"implicit":0,"pageLoad":300000,"script":30000}}}}
That works !!!!!!!

Image

But now ????? what we can do with all that ???? :oops:
I search to see if they are a way for sending an URL location :wink:

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 3:39 pm
by Marc56us
:idea: Add -v to Gecko proxy to see errors messages

Code: Select all

Wbid = RunProgram(driver_location$ ,"-v" ,"",#PB_Program_Open)
(See others options: geckodriver.exe --help)

8) Yes, you need to have Firefox installed because Gecko act as proxy for FF

Next step, build base script (JSON)
Let's let Selenium's macro recorder do the basics for us:

1. Install Selenium IDE in Firefox or in Chrome (this is an extension)
https://www.seleniumhq.org/docs/02_selenium_ide.jsp
2. Click on new icon on FF toolbar
3. Choose "Record a new test in a new project"
4. Do your work in browser as manually
(Right click as new option for Selenium actions, see help)
5. Click Stop Recording (on Selenium IDE)
6. Save script as .side
(edit, modify, etc... read the doc about)
8. Open it in text editor
You have JSON script to use in PureBasic (I think?)

But I haven't gotten that far yet, they're just deductions and the beginning of my tests :oops:

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 4:45 pm
by Kwai chang caine
Thanks a lot Marc, your help is really precious for me 8)

In fact i think the Selenium IDE have not the same script than Geckodriver
Look at :
Gecko script

Code: Select all

{
    "capabilities": {
        "alwaysMatch": {
            "moz:firefoxOptions": {
                "binary": "/usr/local/firefox/bin/firefox",
                "args": ["-headless", "-profile", "/path/to/my/profile"],
                "prefs": {
                    "dom.ipc.processCount": 8
                },
                "log": {
                    "level": "trace"
                }
            }
        }
    }
}
Selenium script

Code: Select all

{
  "id": "a3644216-47a4-4303-afac-90f5df6601f8",
  "version": "1.1",
  "name": "Kcc1",
  "url": "",
  "tests": [{
    "id": "fae891b8-7c77-4d70-8ebc-b02627a07f2f",
    "name": "Kcc1",
    "commands": []
  }],
  "suites": [{
    "id": "835861d4-bb0c-4be4-8d1b-d45b4451e361",
    "name": "Default Suite",
    "persistSession": false,
    "parallel": false,
    "timeout": 300,
    "tests": ["fae891b8-7c77-4d70-8ebc-b02627a07f2f"]
  }],
  "urls": ["https://www.purebasic.com/"],
  "plugins": []
}
And apparently that not works when i send directly Selenium script :oops:

I continue to try to understand :wink: , and believe me...it's not again win :lol:

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 4:50 pm
by Marc56us
My (very small) brain is starting to beep "low battery", but I feel like we're close to finding the solution :!:
The rest tomorrow for me (maybe).

:wink:

Re: Selenium in standalone mode

Posted: Wed Oct 24, 2018 5:27 pm
by Kwai chang caine
but I feel like we're close to finding the solution
That the gods heard you :mrgreen:
The rest tomorrow for me
Ok for me too :wink: ... ten hours of reflection for just open FF, even with a mouse and my foot, i do better :lol: :lol:

Have a good night...without SELENIUM dreams :twisted:

Re: Selenium in standalone mode

Posted: Thu Oct 25, 2018 8:11 am
by zikitrake
Hello!
I am also very interested in this topic. So far I have only worked with webgadget, but some things are very complicated/impossible for me to do.

Based on @CELTIC88 post (http://forums.purebasic.com/english/vie ... 46#p516646), I've added some things, although it's still very difficult for me to understand the Webdriver format.

(I am using chromedriver.exe)

Code: Select all

EnableExplicit

Macro Req(Method,Loc,Cleng)
  Method + " "+Loc+" HTTP/1.1" + #CRLF$ +
           "Connection: Keep-Alive" + #CRLF$ +
           "Content-Type: application/json;charset=utf-8" + #CRLF$ +
           "Accept: */*" + #CRLF$ +
           "User-Agent: Mozilla/4.0" + #CRLF$ +
           "Content-Length: " + Cleng + #CRLF$ +
           #CRLF$ 
EndMacro

InitNetwork()

Procedure.s Webdriver_Req(ConnctionID ,url.s,sData.s,JsGetItem.s,JSONType = #PB_JSON_String,ReqType.s  = "POST")
  Protected pReq$ = Req(ReqType,url,StringByteLength(sData,#PB_Ascii)) + sData
  ;Debug pReq$
  SendNetworkString(ConnctionID,pReq$,#PB_Ascii)
  Protected Size = 1024*1024*10
  Protected *pRepReq = AllocateMemory(Size)
  ReceiveNetworkData(ConnctionID,*pRepReq,Size)
  Protected RepReq.s = StringField(PeekS(*pRepReq,-1,#PB_Ascii),2,#CRLF$ + #CRLF$)
  FreeMemory(*pRepReq)
 
  Protected Jid = ParseJSON(#PB_Any, RepReq) 
  If Jid
    Protected jsV  = JSONValue(Jid)
    If jsV
      Select JSONType
        Case #PB_JSON_Null:    Debug "null"
        Case #PB_JSON_String:  Debug  "string"
          RepReq = GetJSONString(GetJSONMember(jsV, JsGetItem))
        Case #PB_JSON_Number:  Debug  "number"
          RepReq = Str(GetJSONInteger(GetJSONMember(jsV, JsGetItem)))
        Case #PB_JSON_Boolean: Debug  "boolean"
        Case #PB_JSON_Array:   Debug  "array"
        Case #PB_JSON_Object:  Debug  "object"
      EndSelect
    EndIf
  Else
    Debug "JSON error : " + JSONErrorMessage()
  EndIf
  
  ProcedureReturn  RepReq
EndProcedure

Procedure.s Webdriver_ElementGet(Cid, sessionID$, xpath.s)
  Protected json$
  Protected res$  
  json$ = ~"{"
  json$ + ~"\"using\":\"xpath\","
  json$ + ~"\"value\":" + #DQUOTE$ + xpath + #DQUOTE$
  json$ + ~"}"
  res$ = Webdriver_Req(Cid,sessionID$ + "/element", json$, "value",#PB_JSON_Object,"POST")
  
  Debug res$
  ProcedureReturn res$
EndProcedure

Procedure Webdriver_Click(Cid, sessionID$, xpath.s, clickDelay.l = 300)
  Protected json$, res$, elementoID.s, nJS.l
  
  Delay(clickDelay)
  
  json$ = Webdriver_ElementGet(Cid, sessionID$, xpath)
  
  nJS = JSONValue(ParseJSON(#PB_Any,json$))
  elementoID = GetJSONString(GetJSONMember(GetJSONMember(nJS,"value"),"ELEMENT"))
  
  Debug Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/click", "", "",#PB_JSON_Null,"POST")
EndProcedure

Procedure Webdriver_Navigate(Cid, sessionID$, url$)
  Protected json$
  json$ = ~"{"
  json$ + ~"\"url\":" + #DQUOTE$ + url$ + #DQUOTE$
  json$ + ~"}"
  Debug Webdriver_Req(Cid,sessionID$+"/url", json$, "status",#PB_JSON_Number)
  
EndProcedure


DisableExplicit


default_driver_Port = 9515
driver_location$ = "chromedriver.exe"

Wbid = RunProgram(driver_location$ ,"" ,"",#PB_Program_Open)

Cid = OpenNetworkConnection("127.0.0.1",default_driver_Port)

json$ = ~"{"
json$ + ~"  \"desiredCapabilities\": {"
json$ + ~"    \"javascriptEnabled\": true,"
json$ + ~"    \"nativeEvents\": true,"
json$ + ~"    \"browserName\": \"chrome\","
json$ + ~"    \"acceptInsecureCerts\": true,"
json$ + ~"    \"ChromeOptions\": {"
json$ + ~"     \"args\": [\"start-maximized\"]"
json$ + ~"    }"
json$ + ~"  }"
json$ + ~"}"

sessionID$  = "/session/" + Webdriver_Req(Cid,"/session", json$, "sessionId")

Webdriver_Navigate(Cid, sessionID$, "https://www.purebasic.com/")

Debug Webdriver_Req(Cid,sessionID$ + "/title", "", "value",#PB_JSON_String,"GET")

xpath.s = "/html/body/table[1]/tbody/tr[2]/td/table/tbody/tr/td[7]/a"
Webdriver_Click(Cid, sessionID$, xpath)

xpath = "/html/body/table[1]/tbody/tr[5]/td/table/tbody/tr/td/div/table/tbody/tr[5]/td[2]/table/tbody/tr/td/a/img"
Webdriver_Click(Cid, sessionID$, xpath)


CloseNetworkConnection(Cid)

If you see that I don't participate much it's because I know half of what you're saying (my English is very limited!)

I'll pay attention to this thread!

Re: Selenium in standalone mode

Posted: Thu Oct 25, 2018 9:02 am
by Kwai chang caine
Hello ZIKITRAKE :D
And WELCOME to the hell of remoting webbrowser !!!! :twisted:
zikitrake wrote:I am also very interested in this topic
Image

Alléluia !!!!
Another buddy in our island !!! 8)
For the moment, we are three in the world.....but soon we can open a football team :lol:

Image
. So far I have only worked with webgadget
Yes but the problem, WEBGADGET is only IE, and IE is nearly never at the top of the HTML norm, so not work all the time, and several site not like him :|
(I am using chromedriver.exe)
Nobody's perfect !!! :mrgreen: :lol:
If you see that I don't participate much it's because I know half of what you're saying (my English is very limited!)
I'll pay attention to this thread!
Never mind the main thing is to participate even a little bit :wink:
I surely dreaming... :shock:
In more than ten years, it's the first time someone say that to me
In the normal fonction, KCC is always the worst in all subjects ..... unbeatable :mrgreen:
my English is very limited!
And i don't talk to my english
Normally everybody in the world can understand KCC a little bit....except the english :mrgreen:
Excuse me in advance, but i use often this french expression : "I talk english.... like a SPANISH cow" :wink: :lol:

Thanks a lot for your kind answer, your help, and your code 8)
Believe me....we are not too much for hunt the fox...

Image

or the Chrome obviously :wink:

Re: Selenium in standalone mode

Posted: Thu Oct 25, 2018 9:06 am
by Marc56us
Nice code! zikitrake, :)
(Work fine with ChromDriver but not with Firefox (invalid JSON value line 32), but that's another problem.)
We are getting closer and closer to a solution and a simple and elegant solution like any PureBasic product 8)

I had an idea last night. :idea: Since the requests IN and OUT are in JSON format and we have to send a header each time, I wonder if it would not be possible (and even easier) to use the new HTTP_Request() function? instead of SendNetworkString() ?
viewtopic.php?f=14&t=70785&p=527365#p527365

PS. I don't speak a word of English too, I use Deepl.com :P

:wink:

PS. As the solution must be generic and will not necessarily use the Selenium product, I suggest renaming this topic "Driving a Web Browser with PureBasic" (or something like that.) if KCC agrees ?