Driving a Web Browser with PureBasic

Just starting out? Need help? Post your questions and find answers here.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Driving a Web Browser with PureBasic

Post by Kwai chang caine »

Marc56 wrote: I wonder if it would not be possible (and even easier) to use the new HTTP_Request() function
For the moment i not asked to me this style of question... :lol: with or without header....if by miracle FF open... 8)
But the road is open to you :mrgreen:
Marc56 wrote:if KCC agrees
Your desire is orders for KCC :D

If someone understand a little bit the JSON, why the FRED lib say to me : "sessionId" not found and JSONMember = 0 ? :shock:

This is the return of "jsV"
jsV wrote:{"value":{"sessionId":"09e9390e-583c-42cd-8c9e-bcf607e6e2e9","capabilities":{"acceptInsecureCerts":false,"browserName":"firefox","browserVersion":"62.0.2","moz:accessibilityChecks":false,"moz:geckodriverVersion":"0.22.0",
"moz:headless":false,"moz:processID":8008,"moz:profile":"C:\\Users\\Kcc\\AppData\\Local\\Temp\\rust_mozprofile.9JHFI8aLE2Gk",
"moz:useNonSpecCompliantPointerOrigin":false,"moz:webdriverClick":true,"pageLoadStrategy":"normal","platformName":"windows_nt",
"platformVersion":"6.1","rotatable":false,"timeouts":{"implicit":0,"pageLoad":300000,"script":30000}}}}
And JsGetItem is equal to "sessionId"

Code: Select all

JSONMember = GetJSONMember(jsV, JsGetItem)
     
     If JSONMember
      Value$ = GetJSONString(JSONMember)
     Else
      Value$ = "The member ''" + JsGetItem + "'' is not found."
     EndIf
ImageThe happiness is a road...
Not a destination
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Driving a Web Browser with PureBasic

Post by Kwai chang caine »

I answer myself, i never playing with JSON, it's the first time :oops:
The "sessionId" is a subkey of "value"...why ??? i don't know :mrgreen:
Is the reason why the CELTIC code crash :idea:

Code: Select all

Json$ = "{|value|:{|sessionId|:|09e9390e-583c-42cd-8c9e-bcf607e6e2e9|,|capabilities|:{|acceptInsecureCerts|:false,"
Json$ + "|browserName|:|firefox|,|browserVersion|:|62.0.2|,|moz:accessibilityChecks|:false,|moz:geckodriverVersion|:|0.22.0|,"
Json$ + "|moz:headless|:false,|moz:processID|:8008,|moz:profile|:|C:\\Users\\Kcc\\AppData\\Local\\Temp\\rust_mozprofile.9JHFI8aLE2Gk|,"
Json$ + "|moz:useNonSpecCompliantPointerOrigin|:false,|moz:webdriverClick|:true,|pageLoadStrategy|:|normal|,|platformName|:|windows_nt|,|platformVersion|:|6.1|,"
Json$ + "|rotatable|:false,|timeouts|:{|implicit|:0,|pageLoad|:300000,|script|:30000}}}}"

Json$ = ReplaceString(Json$, "|", Chr(34))
Jid = ParseJSON(#PB_Any, Json$)
jsV  = JSONValue(Jid)
JSONMember1 = GetJSONMember(jsV, "value")
Debug JSONMember1
JSONMember2 = GetJSONMember(JSONMember1, "sessionId")
Value$ = GetJSONString(JSONMember2)
Debug Value$
ImageThe happiness is a road...
Not a destination
User avatar
Derren
Enthusiast
Enthusiast
Posts: 313
Joined: Sat Jul 23, 2011 1:13 am
Location: Germany

Re: Driving a Web Browser with PureBasic

Post by Derren »

Use https://jsonlint.com/
It beautifies your JSON Data (and validates it, if you create it yourself with PB or manually)

Now, because of indentation, you can see what is a subkey of what.

Code: Select all

{
	"value": {
		"sessionId": "09e9390e-583c-42cd-8c9e-bcf607e6e2e9",
		"capabilities": {
			"acceptInsecureCerts": false,
			"browserName": "firefox",
			"browserVersion": "62.0.2",
			"moz:accessibilityChecks": false,
			"moz:geckodriverVersion": "0.22.0",
			"moz:headless": false,
			"moz:processID": 8008,
			"moz:profile": "C:\\Users\\Kcc\\AppData\\Local\\Temp\\rust_mozprofile.9JHFI8aLE2Gk",
			"moz:useNonSpecCompliantPointerOrigin": false,
			"moz:webdriverClick": true,
			"pageLoadStrategy": "normal",
			"platformName": "windows_nt",
			"platformVersion": "6.1",
			"rotatable": false,
			"timeouts": {
				"implicit": 0,
				"pageLoad": 300000,
				"script": 30000
			}
		}
	}
}
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Driving a Web Browser with PureBasic

Post by Kwai chang caine »

Hello DERREN (4 in our island) :D

Waoooouuuhhh !!!!
You have right...nothing to see before and after use your "mixer" :D

Image

Super tips !!!! thanks a lot !!! 8) 8) 8)
ImageThe happiness is a road...
Not a destination
Marc56us
Addict
Addict
Posts: 1477
Joined: Sat Feb 08, 2014 3:26 pm

Re: Driving a Web Browser with PureBasic

Post by Marc56us »

:idea: You can also see JSON structure in readeable mode in PB with ShowLibraryViewer("json", value)
Try:

Code: Select all

    Protected Jid = ParseJSON(#PB_Any, RepReq)
    ShowLibraryViewer("json", Jid)
:idea: For others tools: Notepad++ have a plugin to see/arrage JSON file (but not validate) JSToolNpp
http://www.sunjw.us/jstoolnpp/

:wink:
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Driving a Web Browser with PureBasic

Post by Kwai chang caine »

Thanks to this new tips Marc, i don't know it 8)

Now i can :

1/ open FF
2/ Sending url
3/ Apparently have the ID of link
But i'm stopped to the click :|

If someone can help me :wink:

Code: Select all

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

InitNetwork()

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

Procedure.s Webdriver_Req(ConnectionID, 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(ConnectionID, pReq$, #PB_Ascii)
 Protected Size = 1024 * 1024 * 10
 Protected *pRepReq = AllocateMemory(Size)
 ReceiveNetworkData(ConnectionID,*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
   
   JSONMember = GetJSONMember(jsV, JsGetItem)
   
   Select JSONType
     
    Case #PB_JSON_Null
    
     Debug "null"
     
    Case #PB_JSON_String
     
     Debug "string"
     
     If JSONMember
      RepReq = GetJSONString(JSONMember)
     EndIf
     
    Case #PB_JSON_Number:  Debug  "number"
     
     If JSONMember
      RepReq = Str(GetJSONInteger(JSONMember))
     EndIf 
     
    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_FF_GetSessionId(JSONValeur.s)

 Protected Jid = ParseJSON(#PB_Any, JSONValeur)
 
 If Jid
 
  Protected jsV  = JSONValue(Jid)
  
  If jsV
      
   JSONMember1 = GetJSONMember(jsV, "value")
   
   If JSONMember1
    
    JSONMember2 = GetJSONMember(JSONMember1, "sessionId")
    
    If JSONMember2
     SessionId$ = GetJSONString(JSONMember2)
    Else
     SessionId$ = "The member ''SessionId'' is Not found."
    EndIf
    
   Else
      
    SessionId$ = "The member ''Value'' is not found."  
  
   EndIf
   
  Else
  
   Debug "JSON error : " + JSONErrorMessage()
   
  EndIf
  
  ProcedureReturn SessionId$
  
 EndIf
 
EndProcedure

default_driver_Port = 4444
driver_location$ = "geckodriver.exe"

RunProgram(driver_location$ ,"-v --binary " + Chr(34) + "D:/A/J/C/O/Firefox50.1.0/App/Firefox/Firefox.exe" + Chr(34) ,"",#PB_Program_Open)
Cid = OpenNetworkConnection("127.0.0.1", default_driver_Port)
 
Url$ = "{"
Url$ +   "|capabilities|: {"
Url$ +             "|browserName|: |firefox|,"
Url$ +             "|javascriptEnabled|: true,"
Url$ +             "|acceptInsecureCerts|: true,"
Url$ +             "|moz:firefoxOptions|: {"
Url$ +                 "|binary|: |D:/A/J/C/O/Firefox50.1.0/App/Firefox/Firefox.exe|"
Url$ +             "}"
Url$ +     "}"
Url$ + "}"

Answer$ = Webdriver_Req(Cid, "/session", ReplaceString(Url$, "|", Chr(34)), "")
Debug Answer$
SessionId$ = Webdriver_FF_GetSessionId(Answer$)
Debug SessionId$
; 
Url$ = "{|url|:|https://www.purebasic.com/|}"
Webdriver_Req(Cid, "/session/" + SessionId$ + "/url", ReplaceString(Url$, "|", Chr(34)), "status", #PB_JSON_Number)

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

xpath.s = "/html/body/table[1]/tbody/tr[2]/td/table/tbody/tr/td[1]/a"
json$ = "{"
json$ + "|using|:|xpath|,"
json$ + "|value|:|" + xpath + "|"
json$ + "}"
json$ = ReplaceString(json$, "|", Chr(34))
res$ = Webdriver_Req(Cid, "/session/" + sessionID$ + "/element", json$, "value", #PB_JSON_Object, "POST")

Jid = ParseJSON(#PB_Any, res$)
jsV  = JSONValue(Jid)
ObjectValue = GetJSONMember(jsV, "value")
MemberKey$ = JSONMemberKey(ObjectValue)
MemberValue = JSONMemberValue(ObjectValue)
MemberValue$ = GetJSONString(MemberValue)

Debug "Link ID = " + MemberKey$ + ":" + MemberValue$
Debug ""
Debug Webdriver_Req(Cid, "/session/" + sessionID$ + "/element/" + MemberKey$ + ":" + MemberValue$ + "/click", "", "", #PB_JSON_Null, "POST")

CloseNetworkConnection(Cid)
ImageThe happiness is a road...
Not a destination
zikitrake
Addict
Addict
Posts: 834
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: Selenium in standalone mode

Post by zikitrake »

Kwai chang caine wrote:Hello ZIKITRAKE :D
And WELCOME to the hell of remoting webbrowser !!!! :twisted:
Thank you!
Kwai chang caine wrote:"I talk english.... like a SPANISH cow" :wink: :lol:
:lol: :lol: I didn't know that expression, I'll save it for my next excuse!

I just tried your last code with geckodriver.exe, but the ELEMENT ID retrieved has a different format used in Chromedriver. I did a Google search but I don't find nothing about it

PS: If I find anything about Geckodriver I'll let you know!
PS2: I'm big fan about your posts! :D
Marc56us wrote:Nice code! zikitrake, :)
Thank you, I do what I can :D
Marc56us wrote:(Work fine with ChromDriver but not with Firefox (invalid JSON value line 32), but that's another problem.)
Yes, Little change with great different results!
Marc56us wrote:We are getting closer and closer to a solution and a simple and elegant solution like any PureBasic product 8)
Zeus hear you!
Marc56us wrote: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() ?
Please!!! If you do, let us know.
Marc56us wrote:PS. I don't speak a word of English too, I use Deepl.com :P
We are TBTT: The Babel Tower Team :lol:


My last work with Chromedriver:
For now I have added proxy connection (IP:port), Get element ID, Click or send text to an element and run JS.

The last code with simple example:

Code: Select all

; Chromedriver.exe from http://chromedriver.chromium.org
; Based on @CELTIC88 sample http://forums.purebasic.com/english/viewtopic.php?f=13&t=69905&p=516646#p516646
; PB FORUM MAIN THREAD: https://www.purebasic.fr/english/viewtopic.php?f=13&t=71582

EnableExplicit
InitNetwork()

;-============================
;- WD PROCEDURE DECLARES
;-============================
;{
Declare.s Webdriver_Header(Metod.s, Loc.s, Cleng)
Declare.s Webdriver_Req(ConnctionID ,url.s,sData.s,JsGetItem.s,JSONType = #PB_JSON_String,ReqType.s  = "POST")
Declare Webdriver_DesiredCapabilitiesAdd(param$, value$)
Declare Webdriver_ChromeOptionsAdd(param$, value$)
Declare.s Webdriver_NewSession(Cid, proxy.s = "")
Declare.s Webdriver_DeleteSession(Cid, sessionID$)
Declare Webdriver_Navigate(Cid, sessionID$, url$)
Declare Webdriver_NavigateBack(Cid, sessionID$)
Declare Webdriver_NavigateForward(Cid, sessionID$)
Declare Webdriver_Refresh(Cid, sessionID$)
Declare Webdriver_FullScreen(Cid, sessionID$, activated.b = #True)
Declare Webdriver_Resize(Cid, sessionID$, width.l, height.l)
Declare Webdriver_Embedded(Cid, sessionID$, PBParent.l, noHeader = #True, disableForUser = #False)
Declare Webdriver_Keys(Cid, sessionID$, sKeys.s, wdDelay.l = 300)
Declare.s Webdriver_GetUrl(Cid, sessionID$)
Declare.s Webdriver_Title(Cid, sessionID$)
Declare.s Webdriver_Source(Cid, sessionID$)
Declare.s Webdriver_ScreenShot(Cid, sessionID$)
Declare.s Webdriver_CookiesGetAll(Cid, sessionID$, List wdCookies())
Declare Webdriver_CookieAdd(Cid, sessionID$, *cookie)
Declare Webdriver_CookiesDelete(Cid, sessionID$, cookieName$)
Declare.s Webdriver_CookiesDeleteAll(Cid, sessionID$)
Declare.s Webdriver_ElementGetID(Cid, sessionID$, xpath.s)
Declare Webdriver_ElementClick(Cid, sessionID$, xpath.s, clickDelay.l = 300)
Declare Webdriver_ElementValue(Cid, sessionID$, xpath.s, sKeys.s, wdDelay.l = 300)
Declare.s Webdriver_ElementGetText(Cid, sessionID$, xpath.s, wdDelay.l = 500)
Declare.s Webdriver_Execute(Cid, sessionID$, sScript.s, sAsync.b = #False)
;}

;-============================
;- WD GLOBAL VARS
;-============================
Structure wdSTRdesiredCapabilities
  param$
  value$
EndStructure
  Global NewList desiredCapabilities.wdSTRdesiredCapabilities()
Structure wdSTRchromeoptions
  param$
  value$
EndStructure
  Global NewList chromeOptions.wdSTRchromeoptions()

Structure wdSTRcookie
  domain$
  expiry.l
  httpOnly.b
  name$
  path$
  secure.b
  value$    
EndStructure

Macro MacroReq(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
Procedure.s Webdriver_Req(ConnctionID ,url.s,sData.s,JsGetItem.s,JSONType = #PB_JSON_String,ReqType.s  = "POST")  
  Protected pReq$ = MacroReq(ReqType,url,StringByteLength(sData,#PB_Ascii)) + sData
;   Debug "**pReq$**"
;   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)
;   Debug " "
;   Debug "**RepReq$**"
;   Debug RepReq
  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
;-============================
;- WD MAIN PROCEDURES
;-============================
Procedure Webdriver_DesiredCapabilitiesAdd(param$, value$)
  If param$ = "default" And param$ = "default"
    ClearList(desiredCapabilities())
    AddElement(desiredCapabilities()): desiredCapabilities()\param$ = "javascriptEnabled"   : desiredCapabilities()\value$ = "true"
    AddElement(desiredCapabilities()): desiredCapabilities()\param$ = "nativeEvents"        : desiredCapabilities()\value$ = "true"
    AddElement(desiredCapabilities()): desiredCapabilities()\param$ = "browserName"         : desiredCapabilities()\value$ = #DQUOTE$ +"chrome" + #DQUOTE$
    AddElement(desiredCapabilities()): desiredCapabilities()\param$ = "acceptInsecureCerts" : desiredCapabilities()\value$ = "true"    
  Else
    AddElement(desiredCapabilities())
    desiredCapabilities()\param$ = param$
    desiredCapabilities()\value$ = value$  
  EndIf  
EndProcedure
Procedure Webdriver_ChromeOptionsAdd(param$, value$)
  
  AddElement(chromeOptions())
  chromeOptions()\param$ = param$
  chromeOptions()\value$ = value$  
EndProcedure

Procedure.s Webdriver_NewSession(Cid, proxy.s = "")
  ;********************************************************************************
  ; Open a new session with/without proxy and return a new sesion ID
  ; proxy format: IP:PORT...  "10.20.30.40:5060"
  ; global list chromeOptions() used
  ;********************************************************************************
  Protected sessionID$
  Protected json$
  Protected desiredCap$ = ""
  Protected chromeParams$ = ""
  
  ;Read desiredCapabilities list
  If ListSize(desiredCapabilities()) = 0                 ; if desiredCapabilities() is empty, create a default options list
    Webdriver_DesiredCapabilitiesAdd("default", "default")
  EndIf  
  ResetList(desiredCapabilities())
  ForEach(desiredCapabilities())
    With desiredCapabilities()
      If Len(desiredCap$): desiredCap$ + ", " + #LF$: EndIf
      desiredCap$ + "'" + \param$
      If Len(\value$)
        desiredCap$ + "': " + \value$
      EndIf
    EndWith
  Next
  desiredCap$ = ReplaceString(desiredCap$, "'", #DQUOTE$)
  
  ;Fill chromeParams$ from chromeOptions() list
  ResetList(chromeOptions())  
  ForEach(chromeOptions())
    With chromeOptions()
      If Len(chromeParams$): chromeParams$ + ", " + #LF$: EndIf
      chromeParams$ + "'" + \param$
      If Len(\value$)
        chromeParams$ + "=" + \value$
      EndIf
      chromeParams$ + "'"
    EndWith
  Next  
  chromeParams$ = ReplaceString(chromeParams$, "'", #DQUOTE$)
  
  
  json$ = ~"{" + #LF$
  json$ + ~"  |desiredCapabilities|: {" + #LF$
  json$ +       desiredCap$ + "," + #LF$
  json$ + ~"   |chromeOptions|: {" + #LF$
  json$ + ~"     |args|: [" + chromeParams$ + "]" + #LF$  
  json$ + ~"     }" + #LF$  
  ;   ;HAVE A PROXY?
  If proxy
    json$ + ~", |proxy|: {" + #LF$
    json$ + ~"    |proxyType|: |manual|," + #LF$
    json$ + ~"    |httpProxy|: |" + proxy + "|" + #LF$
    json$ + ~"   }" + #LF$
  EndIf
  ;END PROXY JSON
  json$ + ~" }" + #LF$  
  json$ + ~"}"
  
  json$ = ReplaceString(json$, "|", #DQUOTE$)
  
;   ParseJSON(0, json$)
;   json$ = ComposeJSON(0, #PB_JSON_PrettyPrint)
  
  sessionID$  = Webdriver_Req(Cid,"/session", json$, "sessionId")
    
  ProcedureReturn sessionID$  
EndProcedure
Procedure.s Webdriver_DeleteSession(Cid, sessionID$)
  ;********************************************************************************  
  ; Close selected session
  ; Returns: {object} An object describing the session's capabilities.  
  ;********************************************************************************
  Protected res$
  res$ = Webdriver_Req(Cid,sessionID$+"", "", "status",#PB_JSON_Object,"DELETE")  
  ProcedureReturn res$
EndProcedure
;-============================
;- WD NAVIGATION PROCEDURES
;-============================
Procedure Webdriver_Navigate(Cid, sessionID$, url$)
  Protected json$
  json$ = ~"{"
  json$ + ~"\"url\":" + #DQUOTE$ + url$ + #DQUOTE$
  json$ + ~"}"  
  Webdriver_Req(Cid,sessionID$+"/url", json$, "",#PB_JSON_Null)
EndProcedure
Procedure Webdriver_NavigateBack(Cid, sessionID$)
  ;********************************************************************************
  ; Navigate backwards in the browser history, if possible.
  ;********************************************************************************
  Protected status
  status = Val(Webdriver_Req(Cid,sessionID$+"/back", "", "status",#PB_JSON_Number))
  ProcedureReturn status
EndProcedure
Procedure Webdriver_NavigateForward(Cid, sessionID$)
  ;********************************************************************************
  ; Navigate forwards in the browser history, if possible.
  ;********************************************************************************
  Protected status
  status = Val(Webdriver_Req(Cid,sessionID$+"/forward", "", "status",#PB_JSON_Number))
  ProcedureReturn status
EndProcedure
;-============================
;- WD WINDOWS PROCEDURES
;-============================
Procedure Webdriver_Refresh(Cid, sessionID$)
  ;********************************************************************************
  ; Refresh the current page
  ;********************************************************************************
  Protected status
  status = Val(Webdriver_Req(Cid,sessionID$+"/refresh", "", "status",#PB_JSON_Number))
  ProcedureReturn status
EndProcedure
Procedure Webdriver_FullScreen(Cid, sessionID$, activated.b = #True)
  ;********************************************************************************
  ; Maximize the specified window If Not already maximized.
  ; If the :windowHandle URL parameter is "current", the currently active window will be maximized.  
  ;********************************************************************************
  Protected wHandle.s   
  wHandle = Webdriver_Req(Cid,sessionID$+"/window_handle", "", "value",#PB_JSON_String,"GET")    
  Webdriver_Req(Cid,sessionID$+"/window/" + wHandle + "/maximize", "", "",#PB_JSON_Null)  
EndProcedure
Procedure Webdriver_Resize(Cid, sessionID$, width.l, height.l)
  Protected wHandle.s, json$
  
  wHandle = Webdriver_Req(Cid,sessionID$+"/window_handle", "", "value",#PB_JSON_String,"GET")
  
  If Len(wHandle)
    json$ = ~"{"
    json$ + ~"\"width\": " + Str(width) + ", "
    json$ + ~"\"height\": " + Str(height)
    json$ + ~"}"
    
    Webdriver_Req(Cid,sessionID$+"/window/" + wHandle + "/size", json$, "",#PB_JSON_Null)
  EndIf
  
EndProcedure
Procedure Webdriver_Embedded(Cid, sessionID$, PBParent.l, noHeader = #True, disableForUser = #False)
  ;********************************************************************************
  ; PBParent parameter must be a gadgetContainer or a Window
  ; noHeader = #true will hide chromeheader (Tabs, Search bar, Bookmarks bar)
  ; disableForUser = #true to disable parent Gadget/Window
  ;********************************************************************************
  Delay(500)
  Delay(500)
  Protected width.l, height.l
  Protected oldUrl.s
  Protected dataUrl.s
  Protected PBparentHwnd
  Protected chromeTitle.s, chromeHwnd 
  Protected chromeChildTitle.s, chromeChildHwnd 
  Protected rc.rect, chromeY, chromeChildY, chromeYrelative

  oldUrl = Webdriver_GetUrl(Cid, sessionID$)
  dataUrl = URLEncoder(~"data:text/html;charset=utf-8,<!DOCTYPE HTML><title>" + sessionID$ + "</title>")
  Webdriver_Navigate(Cid, sessionID$, dataUrl)

  ;If PBParent is a containerGadget and noHeader = #true then
  ;   create a new containerGadget As child of original PBParent
  ;   and replace PBParent with the new gadget
  If noHeader = #True And IsGadget(PBParent) And GadgetType(PBParent) = #PB_GadgetType_Container
    OpenGadgetList(PBParent)
      Define PBParentNew = ContainerGadget(#PB_Any, 0,0, GadgetWidth(PBParent), GadgetHeight(PBParent), #PB_Container_BorderLess)
    CloseGadgetList()
    If IsGadget(PBParentNew)
      PBParent = PBParentNew
    EndIf
  Else
    noHeader = #False
  EndIf

  ;Resize Chrome Session to PB Parent size  
  If IsGadget(PBParent) And GadgetType(PBParent) = #PB_GadgetType_Container
    width = GadgetWidth(PBParent): height = GadgetHeight(PBParent)
    PBparentHwnd = GadgetID(PBParent)
    HideGadget(PBParent,1)
  ElseIf IsWindow(PBParent)
    width = WindowWidth(PBParent): height = WindowHeight(PBParent)
    PBparentHwnd = WindowID(PBParent)
  Else
    MessageRequester("Error!", "PBParent parameter must be a gadgetContainer or a Window", #PB_MessageRequester_Error)
    ProcedureReturn
  EndIf
  
  Webdriver_Resize(Cid, sessionID$, 1, 1)
  
  ;Search hwnd of the chrome Window opened  
  chromeTitle      = sessionID$ + " - Google Chrome"
  chromeChildTitle = "Chrome_RenderWidgetHostHWND"
  chromeHwnd = FindWindow_(0, chromeTitle) 
  If Not chromeHwnd 
    MessageRequester("Error", chromeTitle + " must be running !") 
    End 
  Else
    chromeChildHwnd = FindWindowEx_(chromeHwnd, 0, chromeChildTitle, 0);
  EndIf   
  
  ; if noHeader = #true, we search Chrome Content part Y position and move up PB Parent Gadget/Window
  ; only works with containerGadget Parent, not when Parent is a windows
  If noHeader And chromeChildHwnd <> 0   
      GetWindowRect_(chromeHwnd,rc)
      chromeY = rc\top
      GetWindowRect_(chromeChildHwnd,rc)
      chromeChildY = rc\top               ; Y from top of screen
      chromeYrelative = chromeChildY-chromeY    ; Y from top of chrome window
      
      ResizeGadget(PBParent, #PB_Ignore, -chromeYrelative, #PB_Ignore, GadgetHeight(PBParent) + chromeYrelative)
    EndIf
    
  Webdriver_Navigate(Cid, sessionID$, oldUrl)
  Webdriver_Resize(Cid, sessionID$, width, height+chromeYrelative)
  
  Webdriver_Refresh(Cid, sessionID$)
  
  
  ; Set Chrome as child of PB Parent
  If PBparentHwnd          
    SetWindowLong_(chromeHwnd, #GWL_STYLE, GetWindowLong_(chromeHwnd, #GWL_STYLE) &(~(#WS_MAXIMIZE|#WS_SIZEBOX )))
    SetParent_(chromeHwnd, PBparentHwnd) 
    SetWindowPos_(chromeHwnd, 0, 0, 0, 0, 0, #SWP_NOSIZE|#SWP_NOZORDER|#SWP_FRAMECHANGED)           
  EndIf
 
  
  If IsGadget(PBParent)
    DisableGadget(PBParent, disableForUser)
    HideGadget(PBParent,0)
  ElseIf IsWindow(PBParent)
    DisableWindow(PBParent, disableForUser)
  EndIf  
 
  
EndProcedure
;-============================
;- WD GENERAL PROCEDURES
;-============================
Procedure Webdriver_Keys(Cid, sessionID$, sKeys.s, wdDelay.l = 300)
  ;********************************************************************************
  ; Send keys to the session
  ; EXAMPLE:
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementValue(Cid, sessionID$, xpath, "Hello, world!")
  ;********************************************************************************
  Protected json$

  Delay(wdDelay)
  
  json$ =  "{" + #LF$
  json$ + ~"\"value\": [" + #DQUOTE$ + sKeys + #DQUOTE$ + "]" + #LF$
  json$ + ~"}"
  
  Webdriver_Req(Cid,sessionID$ + "/keys", json$, "",#PB_JSON_Null)
EndProcedure
Procedure.s Webdriver_GetUrl(Cid, sessionID$)
  ;********************************************************************************
  ; Retrieve the URL of the current page.
  ;********************************************************************************
  Protected url$
  url$ = Webdriver_Req(Cid,sessionID$+"/url", "", "value",#PB_JSON_String, "GET")
  ProcedureReturn(url$)
EndProcedure
Procedure.s Webdriver_Title(Cid, sessionID$)
  ;********************************************************************************
  ; Get the current page title.
  ;********************************************************************************
  Protected title$
  title$ = Webdriver_Req(Cid,sessionID$ + "/title", "", "value",#PB_JSON_String,"GET")  
  ProcedureReturn(title$)
EndProcedure
Procedure.s Webdriver_Source(Cid, sessionID$)
  ;********************************************************************************
  ; Return the source code
  ;********************************************************************************
  ProcedureReturn Webdriver_Req(Cid,sessionID$+"/source", "", "value",#PB_JSON_String,"GET")
EndProcedure
Procedure.s Webdriver_ScreenShot(Cid, sessionID$)
  ;********************************************************************************
  ; Take a screenshot of the current page.
  ; Returns string with the screenshot As a base64 encoded PNG.
  ;********************************************************************************
  Protected status.l, value.s
  status = Val(Webdriver_Req(Cid,sessionID$+"/screenshot", "", "status",#PB_JSON_Number,"GET"))
  If status = 0
    value = Webdriver_Req(Cid,sessionID$+"/screenshot", "", "value",#PB_JSON_String,"GET")
  EndIf
  
  ProcedureReturn value
EndProcedure
Procedure.s Webdriver_CookiesGetAll(Cid, sessionID$, List wdCookies.wdSTRcookie())
  ;********************************************************************************  
  ;  Retrieve all cookies visible to the current page  
  ;  Example:
  ;               NewList theCookies.wdSTRcookie()
  ;               Webdriver_CookiesGetAll(Cid, sessionID$, theCookies())
  ;               ForEach(theCookies())
  ;                 Debug theCookies()\name$
  ;                 Debug theCookies()\value$
  ;               Next  
  ;********************************************************************************
  Protected json$, jsO, jsV, objectValue.l
  
  json$ = Webdriver_Req(Cid,sessionID$+"/cookie", "", "value",#PB_JSON_Object,"GET")  
  
  jsO = ParseJSON(#PB_Any, json$)
  jsV  = JSONValue(jsO)
  objectValue = GetJSONMember(jsV, "value")
  
  ClearList(wdCookies())
  ExtractJSONList(objectValue, wdCookies())
  
EndProcedure
Procedure Webdriver_CookieAdd(Cid, sessionID$, *cookie.wdSTRcookie)
  ;********************************************************************************  
  ; Set a cookie. If the cookie path is not specified, it should be set to "/".
  ; Likewise, If the domain is omitted, it should Default To the current page's domain.  
  ; Example:
  ;             myCookie.wdSTRcookie
  ;             myCookie\name$ = "pbcookie"
  ;             myCookie\value$ = "Webdriver in PB, yeah!"
  ;             Webdriver_CookieAdd(Cid, sessionID$, myCookie)
  ;********************************************************************************
  Protected json$, status
  Protected secure.s   = "false"
  Protected httpOnly.s = "false"
  
  With *cookie
    If \httpOnly: httpOnly = "true": EndIf
    If \secure: secure = "true": EndIf
    
    json$ = ~"{"
    json$ + ~"  \"cookie\": {"    + #LF$
    json$ + ~"    \"domain\":"    + #DQUOTE$ + \domain$   + #DQUOTE$ + "," + #LF$
    json$ + ~"    \"expiry\":"    + #DQUOTE$ + \expiry    + #DQUOTE$ + "," + #LF$
    json$ + ~"    \"httpOnly\":"  + httpOnly + "," + #LF$
    json$ + ~"    \"name\":"      + #DQUOTE$ + \name$     + #DQUOTE$ + "," + #LF$
    json$ + ~"    \"path\":"      + #DQUOTE$ + \path$     + #DQUOTE$ + "," + #LF$
    json$ + ~"    \"secure\":"    + secure + "," + #LF$
    json$ + ~"    \"value\":"     + #DQUOTE$ + \value$    + #DQUOTE$ + ""
    json$ + ~"  }"
    json$ + ~"}"
    
  EndWith
  
  status = Val( Webdriver_Req(Cid,sessionID$+"/cookie", json$, "status",#PB_JSON_Number,"POST")  )
  ProcedureReturn status
  
EndProcedure

Procedure Webdriver_CookiesDelete(Cid, sessionID$, cookieName$)
  ;********************************************************************************
  ; Delete the cookie with the given name
  ;********************************************************************************
  Protected status
  status = Val (Webdriver_Req(Cid,sessionID$+"/cookie/" + cookieName$, "", "status",#PB_JSON_Number,"DELETE"))
  ProcedureReturn status
EndProcedure
Procedure.s Webdriver_CookiesDeleteAll(Cid, sessionID$)
  ;********************************************************************************
  ; Delete all cookies visible to the current page.
  ;********************************************************************************
  Webdriver_Req(Cid,sessionID$+"/cookie", "", "",#PB_JSON_Null,"DELETE")  
EndProcedure
;-============================
;- WD ELEMENTS PROCEDURES
;-============================
Procedure.s Webdriver_ElementGetID(Cid, sessionID$, xpath.s)
  ;********************************************************************************
  ; Return ID of an element
  ;********************************************************************************
  Protected json$, nJS.l
  Protected status, value$
  
  json$ = ~"{"
  json$ + ~"\"using\":\"xpath\","
  json$ + ~"\"value\":" + #DQUOTE$ + xpath + #DQUOTE$
  json$ + ~"}"
  
  value$ = Webdriver_Req(Cid,sessionID$ + "/element", json$, "value",#PB_JSON_Object,"POST")
  
  nJS = ParseJSON(#PB_Any, value$)
  
  If IsJSON(nJS)  
    nJS = JSONValue(nJS)
    status = GetJSONInteger(GetJSONMember(nJS, "status"))
    If status = 0
      value$ = GetJSONString(GetJSONMember(GetJSONMember(nJS, "value"), "ELEMENT"))
    Else
      value$ = ""
    EndIf
  Else
    value$ = ""
  EndIf
  
  ProcedureReturn value$
EndProcedure
Procedure Webdriver_ElementClick(Cid, sessionID$, xpath.s, clickDelay.l = 300)
  ;********************************************************************************
  ; Click in element
  ; EXAMPLE:   
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementClick(Cid, sessionID$, xpath) 
  ;********************************************************************************
  Protected elementoID.s
  
  Delay(clickDelay)  
  
  elementoID = Webdriver_ElementGetID(Cid, sessionID$, xpath)   
  Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/click", "", "",#PB_JSON_Null,"POST")  
EndProcedure
Procedure Webdriver_ElementValue(Cid, sessionID$, xpath.s, sKeys.s, wdDelay.l = 300)
  ;********************************************************************************
  ; Type text in an element
  ; EXAMPLE:
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementValue(Cid, sessionID$, xpath, "Hello, world!")
  ;********************************************************************************
  Protected json$, elementoID.s
    
  Delay(wdDelay)
  
  elementoID = Webdriver_ElementGetID(Cid, sessionID$, xpath)  
  
  json$ =  "{" + #LF$
  json$ + ~"\"value\": [" + #DQUOTE$ + sKeys + #DQUOTE$ + "]" + #LF$
  json$ + ~"}"
  
  Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/value", json$, "",#PB_JSON_Null)
EndProcedure
Procedure.s Webdriver_ElementGetText(Cid, sessionID$, xpath.s, wdDelay.l = 500)
  ;********************************************************************************
  ; Get text in an element
  ; EXAMPLE:
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementValue(Cid, sessionID$, xpath, "Hello, world!")
  ;********************************************************************************
  Protected elementoID.s
  Protected status, value$
  
  Delay(wdDelay)
  
  status = 0
  value$  = ""
  
  elementoID = Webdriver_ElementGetID(Cid, sessionID$, xpath)  
  
  If elementoID
    status = Val( Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/text", "", "status",#PB_JSON_Number, "GET") )
    If status = 0 ; OK?
      value$ = Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/text", "", "value",#PB_JSON_String, "GET")
    EndIf
  EndIf
    
  ProcedureReturn value$
  
EndProcedure
;-============================
;- WD SCRIPTS PROCEDURES
;-============================
Procedure.s Webdriver_Execute(Cid, sessionID$, sScript.s, sAsync.b = #False)
  ;********************************************************************************
  ; Execute an script sync or async, depending of sAsync var value
  ; EXAMPLE:
  ;         Webdriver_Execute(Cid,sessionID$, "alert('hello');")
  ;         devuelve STATUS|MESSAGE
  ;********************************************************************************
  Protected json$, res$, nJS.l, Async$, status, message.s
  
  If sAsync
    Async$ = "_async"
  Else
    Async$ = ""
  EndIf
  
  json$ = ~"{" + #LF$
  json$ + ~"\"script\": " + #DQUOTE$ + sScript + #DQUOTE$ + #LF$
  json$ + ~", \"args\": []" + #LF$  
  json$ + ~"}" + #LF$  
  
  res$ = Webdriver_Req(Cid, sessionID$ + "/execute" + Async$, json$, "", #PB_JSON_Object)
  
  nJS = ParseJSON(#PB_Any, res$)
  If IsJSON(nJS)
    nJS = JSONValue(nJS)
    status = GetJSONInteger(GetJSONMember(nJS, "status"))
    If status = 0
      message = "OK"
    Else      
      message = GetJSONString(GetJSONMember(GetJSONMember(nJS, "value"), "message"))
    EndIf      
    res$ = Str(status) + "|" + message    
  EndIf
  
  ProcedureReturn res$
  
EndProcedure



;-============================
;- WEBDRIVER EXAMPLE
;-============================
CompilerIf #PB_Compiler_IsMainFile 
  DisableExplicit
  InitNetwork()
  
  default_driver_Port = 9515
  driver_location$ = "chromedriver.exe"
  Wbid = RunProgram(driver_location$ ,"" ,"",#PB_Program_Open)
  
  Cid = OpenNetworkConnection("127.0.0.1",default_driver_Port)
  
  Webdriver_DesiredCapabilitiesAdd("default", "default")
  ClearList(chromeOptions())
  Webdriver_ChromeOptionsAdd("--window-size", "650,480")  
  sessionID$  = "/session/" + Webdriver_NewSession(Cid, "")
  
  Webdriver_Navigate(Cid, sessionID$, "https://www.purebasic.fr/english/")
  
  xpath.s = "//*[@id='menubar']/table/tbody/tr/td[1]/a[2]"
  Webdriver_ElementClick(Cid, sessionID$, xpath)
  
  xpath.s = "//*[@id='pagecontent']/form/table/tbody/tr[2]/td[2]/input[1]"
  Webdriver_ElementValue(Cid, sessionID$, xpath, "Chromedriver")
  Webdriver_ElementValue(Cid, sessionID$, xpath, "\n")
  
  
  Delay(2000)
  Webdriver_DeleteSession(Cid, sessionID$)
  CloseNetworkConnection(Cid)
  KillProgram(Wbid)
  CloseProgram(Wbid)  
  Delay(1000)
CompilerEndIf


;-============================
;- WEBDRIVER EMBEDDED EXAMPLE
;-============================
CompilerIf #PB_Compiler_IsMainFile 
  
  DisableExplicit
  InitNetwork()
  
  ;Create a window with a container
  mainWindow = OpenWindow(#PB_Any, 0, 0, 800, 600, "PB WINDOWS with a containerGadget", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget) 
  containerG = ContainerGadget(#PB_Any, 50,50, 700,500, #PB_Container_BorderLess)  
  CloseGadgetList()  
  SetGadgetColor(containerG, #PB_Gadget_BackColor, $BFBF3F)
  While WindowEvent(): Wend  
  
  default_driver_Port = 9515
  Wbid = RunProgram(driver_location$ ,"" ,"",#PB_Program_Open|#PB_Program_Hide)
    
  Cid = OpenNetworkConnection("127.0.0.1",default_driver_Port)
  
  Webdriver_DesiredCapabilitiesAdd("default", "default")
  ClearList(chromeOptions())
  Webdriver_ChromeOptionsAdd("--window-size", "100,100")
  Webdriver_ChromeOptionsAdd("--window-position", "-1000,-1000")
  
  sessionID$  = "/session/" + Webdriver_NewSession(Cid, "")
  
  
  Webdriver_Embedded(Cid, sessionID$, containerG, #True)
  
  Webdriver_Navigate(Cid, sessionID$, "https://www.purebasic.fr/english/")
  
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
  
  Debug "Delete: " + Webdriver_DeleteSession(Cid, sessionID$)
  
  CloseNetworkConnection(Cid)
  KillProgram(Wbid)
  CloseProgram(Wbid)
  
CompilerEndIf
Last edited by zikitrake on Sun Oct 28, 2018 11:05 pm, edited 1 time in total.
zikitrake
Addict
Addict
Posts: 834
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: Driving a Web Browser with PureBasic

Post by zikitrake »

Updated previous code with an example of embedded Chrome in a containerGagdet
User avatar
CELTIC88
Enthusiast
Enthusiast
Posts: 154
Joined: Thu Sep 17, 2015 3:39 pm

Re: Driving a Web Browser with PureBasic

Post by CELTIC88 »

hi cck :D,
PS: I love CELTIC too !!! :D
I love you too ahamm my friend :D

good job @zikitrake,
Currently I'm using "https://bitbucket.org/chromiumembedded/cef"
good luck for you :)
interested in Cybersecurity..
zikitrake
Addict
Addict
Posts: 834
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: Driving a Web Browser with PureBasic

Post by zikitrake »

CELTIC88 wrote:hi cck :D,
PS: I love CELTIC too !!! :D
I love you too ahamm my friend :D

good job @zikitrake,
Currently I'm using "https://bitbucket.org/chromiumembedded/cef"
good luck for you :)
Thank you, Celtic88 you inspired me with your code in the other thread!

I've been watching CEF for a while, but I'm afraid my knowledge doesn't allow me to know how to get started.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Driving a Web Browser with PureBasic

Post by Kwai chang caine »

zikitrake wrote:PS2: I'm big fan about your posts! :D
Thanks a lot for this kinds words go directly in my heart 8)
I try to put a little bit of good humor in all the programmers friends lifes, in exchange of all their precious and generous helps.
Programming is too much often hards after reflect numerous hours and not always have the morale :|
I always say, the humor is not the ennemy of the serious things :wink: and sometime take the things with a little bit more lightness can help to have new good ideas
Again thanks 8)

Excuse me for the late answer, i'm forcing to go far away of a PC in family by my wife :?
zikitrake wrote:I just tried your last code with geckodriver.exe, but the ELEMENT ID retrieved has a different format used in Chromedriver
Yes you have right i see that :shock: :wink:
My answer is
{"value":{"sessionId":"358f0cfd-d7cc-4b5b-be09-cf3cffb536a7","capabilities":{"acceptInsecureCerts":false,"browserName":"firefox","browserVersion":"63.0","moz:accessibilityChecks":false,
"moz:geckodriverVersion":"0.22.0","moz:headless":false,"moz:processID":7772,
"moz:profile":"C:\\Users\\kcc\\AppData\\Local\\Temp\\rust_mozprofile.CcZdw6OUdHlg","moz:useNonSpecCompliantPointerOrigin":false,
"moz:webdriverClick":true,"pageLoadStrategy":"normal","platformName":"windows","platformVersion":"10.0",
"rotatable":false,"setWindowRect":true,"timeouts":{"implicit":0,"pageLoad":300000,"script":30000},"unhandledPromptBehavior":"dismiss and notify"}}}
358f0cfd-d7cc-4b5b-be09-cf3cffb536a7
and i have try

Code: Select all

/session/358f0cfd-d7cc-4b5b-be09-cf3cffb536a7/url
that not works :|

I have try your splendid code, and it works very well on W10 without proxy
I can't try it behind a PROXY, because i'm not in my enterprise this week, but as soon i can, i'm very interesting to try your code with a PROXY 8)

CHROME, CHROME..always CHROME ...ok talking about CHROME :? :lol: :lol:

Since only CHROME works for the moment, can you adding in your great code a remote for a CHROME portable ?
Like for Firefox, that can be usefull for use the RemoteBrowser on an USB key :wink:

Code: Select all

Url$ +             "|moz:firefoxOptions|: {"
Url$ +                 "|binary|: |" + Firefox + "|"
Url$ +             "}"
Url$ +     "}"
I hate all the installing software :twisted:

Again thanks for your code, you help to move very much in this adventure 8)
CELTIC88 wrote:I love you too ahamm my friend :D
Your kinds words are an honor MASTER, for little KCC 8)

Image
ImageThe happiness is a road...
Not a destination
zikitrake
Addict
Addict
Posts: 834
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: Driving a Web Browser with PureBasic

Post by zikitrake »

You don't have to excuse yourself, it's the weekend :!:

I also prefer portable applications (that's why I use purebasic and not .net).

Where do I download a portable version of Firefox? Isn't there an official version? :?:

(And if you know any reliable version of Chrome, I'd appreciate it too 8) )
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Driving a Web Browser with PureBasic

Post by Kwai chang caine »

You don't have to excuse yourself, it's the weekend :!:
Thanks to understand 8)
But even to go to the toilet ....

Image

the time is long without PB :cry:
Fortunaltely......there is phone portable

I also prefer portable applications (that's why I use purebasic and not .net).
Exactely like me :D
Since i have see PB is standalone (And other advantages obviously :wink:), i have abandon the other langages
Before i use VB6, and now since VB6 is an old software,.. portable version exist (non official)
That proof, even a software like VB6 really integrating in BDR can works without installing :? :shock:

A site create versions (non official) of numerous software
It's not always the last version, but personally i use this versions since several years without problem
And i have see, even this portable version auto update alone and continue to be portable :shock:
Like this i can use old code, old addons, etc...when i want
Like PB, i play with the differentes versions besides, all that on a external DD 8)

Firefox
https://portableapps.com/apps/internet/firefox_portable

Chrome
https://portableapps.com/apps/internet/ ... e_portable

The portability...

Image

Is the freedom !!! :D
ImageThe happiness is a road...
Not a destination
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Driving a Web Browser with PureBasic

Post by Kwai chang caine »

I have again searching all the day without real succes :|
Always impossible to send the elementID and click on a link

Just learn apparently the ID of element is the second part after the ":"

Code: Select all

element-6066-11e4-a52e-4f735466cecf:b3047924-f191-46b8-986b-aa767bd7bd95
so

Code: Select all

b3047924-f191-46b8-986b-aa767bd7bd95
But after ...nothing works, when i send to GeckoDriver

Code: Select all

POST /session/0bc877c3-7da2-44e8-b019-0b7a85b208ef/element/b3047924-f191-46b8-986b-aa767bd7bd95/click HTTP/1.1
Connection: Keep-Alive
Content-Type: application/json;charset=utf-8
Accept: */*
User-Agent: Mozilla/4.0
Content-Length: 0

always the same answer of Geckodriver
{"value":{"error":"invalid argument","message":"Failed to decode request as JSON: ","stacktrace":"Syntax error at :1:0"}}
Perhaps also a FF bug, because they are several issue reporting about this subject

I'm desperate, i'm sure we are not really far of the solution, but it was too good to be true, i believe my search stop here, for again another method, more simple :cry:
Not enough example, nobody have really the good idea of directly command GeckoDriver
Everybody pass by Selenium, with PYTHON, RUBY, PHP, JAVASCRIPT....either use the simplicity with OOP langages :|
ImageThe happiness is a road...
Not a destination
zikitrake
Addict
Addict
Posts: 834
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: Driving a Web Browser with PureBasic

Post by zikitrake »

Kwai chang caine wrote:I have again searching all the day without real succes :|
Always impossible to send the elementID and click on a link|
Hi, sorry for slow reply, finally, I got an example for Firefox Portable :)

For now, It only works with Navigate and Click Elements, but if you see the Click code you could try to make other commands :)

The code with Firefox example added:

Code: Select all

; Chromedriver.exe from http://chromedriver.chromium.org
; Based on @CELTIC88 sample http://forums.purebasic.com/english/viewtopic.php?f=13&t=69905&p=516646#p516646
; PB FORUM MAIN THREAD: https://www.purebasic.fr/english/viewtopic.php?f=13&t=71582

EnableExplicit
InitNetwork()

;-============================
;- WD PROCEDURE DECLARES
;-============================
;{
Declare.s Webdriver_Header(Metod.s, Loc.s, Cleng)
Declare.s Webdriver_Req(ConnctionID ,url.s,sData.s,JsGetItem.s,JSONType = #PB_JSON_String,ReqType.s  = "POST")
Declare Webdriver_DesiredCapabilitiesAdd(param$, value$)
Declare Webdriver_ChromeOptionsAdd(param$, value$)
Declare.s Webdriver_NewSession(Cid, wdProxy.s = "")
Declare.s Webdriver_DeleteSession(Cid, sessionID$)
Declare Webdriver_Navigate(Cid, sessionID$, url$)
Declare Webdriver_NavigateBack(Cid, sessionID$)
Declare Webdriver_NavigateForward(Cid, sessionID$)
Declare Webdriver_Refresh(Cid, sessionID$)
Declare Webdriver_FullScreen(Cid, sessionID$, activated.b = #True)
Declare Webdriver_Resize(Cid, sessionID$, width.l, height.l)
Declare Webdriver_Embedded(Cid, sessionID$, PBParent.l, noHeader = #True, disableForUser = #False)
Declare Webdriver_Keys(Cid, sessionID$, sKeys.s, wdDelay.l = 300)
Declare.s Webdriver_GetUrl(Cid, sessionID$)
Declare.s Webdriver_Title(Cid, sessionID$)
Declare.s Webdriver_Source(Cid, sessionID$)
Declare.s Webdriver_ScreenShot(Cid, sessionID$)
Declare.s Webdriver_CookiesGetAll(Cid, sessionID$, List wdCookies())
Declare Webdriver_CookieAdd(Cid, sessionID$, *cookie)
Declare Webdriver_CookiesDelete(Cid, sessionID$, cookieName$)
Declare.s Webdriver_CookiesDeleteAll(Cid, sessionID$)
Declare.s Webdriver_ElementGetID(Cid, sessionID$, xpath.s)
Declare Webdriver_ElementClick(Cid, sessionID$, xpath.s, wdDelay.l = 300)
Declare Webdriver_ElementValue(Cid, sessionID$, xpath.s, sKeys.s, wdDelay.l = 300)
Declare.s Webdriver_ElementGetText(Cid, sessionID$, xpath.s, wdDelay.l = 500)
Declare.s Webdriver_Execute(Cid, sessionID$, sScript.s, arguments$, sAsync.b = #False)
Declare WebDriver_SetFocusByClassName (Cid, sessionID$, sFieldClassName.s, idxTag.s="0", valueAdd.b = #False, nuevoValue.s = "", innerHTML.s="", hacerClick.b=#False, TeclaEnter.b = #False, innerText.s = "")
Declare Webdriver_ElementClear(Cid, sessionID$, xpath.s, wdDelay.l = 300)
;}

;-============================
;- WD GLOBAL VARS
;-============================
Global wdBrowser.s = "chrome"
Structure wdSTRdesiredCapabilities
  param$
  value$
EndStructure
  Global NewList desiredCapabilities.wdSTRdesiredCapabilities()
Structure wdSTRchromeoptions
  param$
  value$
EndStructure
  Global NewList chromeOptions.wdSTRchromeoptions()

Structure wdSTRcookie
  domain$
  expiry.l
  httpOnly.b
  name$
  path$
  secure.b
  value$    
EndStructure

Procedure.s MacroReq(Method.s,Loc.s,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: " + Str(Cleng) + #CRLF$ +
           #CRLF$ 
  ProcedureReturn Method
EndProcedure
Procedure.s Webdriver_Req(ConnctionID ,url.s,sData.s,JsGetItem.s,JSONType = #PB_JSON_String,ReqType.s  = "POST")  
  Protected pReq$ = MacroReq(ReqType,url,StringByteLength(sData,#PB_Ascii)) + sData
;   Debug "**pReq$**"
;   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)
;   Debug " "
;   Debug "**RepReq$**"
;   Debug RepReq
  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
;-============================
;- WD MAIN PROCEDURES
;-============================
  Procedure Webdriver_DesiredCapabilitiesAdd(param$, value$)
  Protected replaced.b = #False
  
  If param$ = "default" And value$ = "default"
    ClearList(desiredCapabilities())
    AddElement(desiredCapabilities()): desiredCapabilities()\param$ = "javascriptEnabled"   : desiredCapabilities()\value$ = "true"
    AddElement(desiredCapabilities()): desiredCapabilities()\param$ = "nativeEvents"        : desiredCapabilities()\value$ = "true"
    AddElement(desiredCapabilities()): desiredCapabilities()\param$ = "browserName"         : desiredCapabilities()\value$ = #DQUOTE$ + wdBrowser + #DQUOTE$
    AddElement(desiredCapabilities()): desiredCapabilities()\param$ = "acceptInsecureCerts" : desiredCapabilities()\value$ = "true"    
  Else
    ResetList(desiredCapabilities())
    ForEach(desiredCapabilities())
      If desiredCapabilities()\param$ = param$
        desiredCapabilities()\value$ = value$
        replaced = #True
        Break 
      EndIf
    Next
    
    If replaced = #False
      AddElement(desiredCapabilities())
      desiredCapabilities()\param$ = param$
      desiredCapabilities()\value$ = value$  
    EndIf
    
  EndIf  
EndProcedure

Procedure Webdriver_ChromeOptionsAdd(param$, value$)
  Protected replaced.b = #False
  
  ResetList(chromeOptions())
  ForEach(chromeOptions())
    If chromeOptions()\param$ = param$
      chromeOptions()\value$ = value$
      replaced = #True
      Break 
    EndIf
  Next
  
  If replaced = #False
    AddElement(chromeOptions())
    chromeOptions()\param$ = param$
    chromeOptions()\value$ = value$  
  EndIf
  
EndProcedure

Procedure.s Webdriver_NewSession(Cid, wbProxy.s = "")
  ;********************************************************************************
  ; Open a new session with/without proxy and return a new sesion ID
  ; wbProxy format: IP:PORT...  "10.20.30.40:5060"
  ; global list chromeOptions() used
  ;********************************************************************************
  Protected sessionID$
  Protected json$, json
  Protected desiredCap$ = ""
  Protected chromeParams$ = ""
  
  ;Read desiredCapabilities list
  If ListSize(desiredCapabilities()) = 0                 ; if desiredCapabilities() is empty, create a default options list
    Webdriver_DesiredCapabilitiesAdd("default", "default")
  EndIf  
  ResetList(desiredCapabilities())
  ForEach(desiredCapabilities())
    With desiredCapabilities()
      If Len(desiredCap$): desiredCap$ + ", " + #LF$: EndIf
      desiredCap$ + "'" + \param$
      If Len(\value$)
        desiredCap$ + "': " + \value$
      EndIf
    EndWith
  Next
  desiredCap$ = ReplaceString(desiredCap$, "'", #DQUOTE$)
  
  ;Fill chromeParams$ from chromeOptions() list
  ResetList(chromeOptions())  
  ForEach(chromeOptions())
    With chromeOptions()
      If Len(chromeParams$): chromeParams$ + ", " + #LF$: EndIf
      chromeParams$ + "'" + \param$
      If Len(\value$)
        chromeParams$ + "=" + \value$
      EndIf
      chromeParams$ + "'"
    EndWith
  Next  
  chromeParams$ = ReplaceString(chromeParams$, "'", #DQUOTE$)
  
  
  json$ = ~"{" + #LF$
  json$ + ~"  |desiredCapabilities|: {" + #LF$
  json$ +       desiredCap$ + #LF$
    ; IS CHROME?  
  If wdBrowser = "chrome"
    json$ + ~",   |chromeOptions|: {" + #LF$
    json$ + ~"     |args|: [" + chromeParams$ + "]" + #LF$  
    json$ + ~"     }" + #LF$  
  EndIf
  
    ; HAVE A PROXY?
  If wbProxy
    json$ + ~", |proxy|: {" + #LF$
    json$ + ~"    |proxyType|: |manual|," + #LF$
    json$ + ~"    |httpProxy|: |" + wbProxy + "|" + #LF$
    json$ + ~"   }" + #LF$
  EndIf
  ;END PROXY JSON
  
  json$ + ~" }" + #LF$  
  json$ + ~"}"
  
  json$ = ReplaceString(json$, "|", #DQUOTE$)
  
   ParseJSON(0, json$)
   json$ = ComposeJSON(0, #PB_JSON_PrettyPrint)
   Debug json$
   
   Select wdBrowser
       
    Case "chrome"
      sessionID$  = Webdriver_Req(Cid,"/session", json$, "sessionId")
    Case "firefox"
      json$ = Webdriver_Req(Cid,"/session", json$, "value", #PB_JSON_Object)
      jSON = ParseJSON(#PB_Any, json$)
      sessionID$ = GetJSONString(GetJSONMember(GetJSONMember(JSONValue(jSON), "value"), "sessionId"))
  EndSelect
    
  ProcedureReturn sessionID$  
EndProcedure
Procedure.s Webdriver_DeleteSession(Cid, sessionID$)
  ;********************************************************************************  
  ; Close selected session
  ; Returns: {object} An object describing the session's capabilities.  
  ;********************************************************************************
  Protected res$
  res$ = Webdriver_Req(Cid,sessionID$+"", "", "status",#PB_JSON_Object,"DELETE")  
  ProcedureReturn res$
EndProcedure
;-============================
;- WD NAVIGATION PROCEDURES
;-============================
Procedure Webdriver_Navigate(Cid, sessionID$, url$)
  Protected json$, status.l
  json$ = ~"{"
  json$ + ~"\"url\":" + #DQUOTE$ + url$ + #DQUOTE$
  json$ + ~"}"  
  status = Val (Webdriver_Req(Cid,sessionID$+"/url", json$, "",#PB_JSON_Null))
  ProcedureReturn status  
EndProcedure
Procedure Webdriver_NavigateBack(Cid, sessionID$)
  ;********************************************************************************
  ; Navigate backwards in the browser history, if possible.
  ;********************************************************************************
  Protected status
  status = Val(Webdriver_Req(Cid,sessionID$+"/back", "", "status",#PB_JSON_Number))
  ProcedureReturn status
EndProcedure
Procedure Webdriver_NavigateForward(Cid, sessionID$)
  ;********************************************************************************
  ; Navigate forwards in the browser history, if possible.
  ;********************************************************************************
  Protected status
  status = Val(Webdriver_Req(Cid,sessionID$+"/forward", "", "status",#PB_JSON_Number))
  ProcedureReturn status
EndProcedure
;-============================
;- WD WINDOWS PROCEDURES
;-============================
Procedure Webdriver_Refresh(Cid, sessionID$)
  ;********************************************************************************
  ; Refresh the current page
  ;********************************************************************************
  Protected status
  status = Val(Webdriver_Req(Cid,sessionID$+"/refresh", "", "status",#PB_JSON_Number))
  ProcedureReturn status
EndProcedure
Procedure Webdriver_FullScreen(Cid, sessionID$, activated.b = #True)
  ;********************************************************************************
  ; Maximize the specified window If Not already maximized.
  ; If the :windowHandle URL parameter is "current", the currently active window will be maximized.  
  ;********************************************************************************
  Protected wHandle.s   
  wHandle = Webdriver_Req(Cid,sessionID$+"/window_handle", "", "value",#PB_JSON_String,"GET")    
  Webdriver_Req(Cid,sessionID$+"/window/" + wHandle + "/maximize", "", "",#PB_JSON_Null)  
EndProcedure
Procedure Webdriver_Resize(Cid, sessionID$, width.l, height.l)
  Protected wHandle.s, json$
  
  wHandle = Webdriver_Req(Cid,sessionID$+"/window_handle", "", "value",#PB_JSON_String,"GET")
  
  If Len(wHandle)
    json$ = ~"{"
    json$ + ~"\"width\": " + Str(width) + ", "
    json$ + ~"\"height\": " + Str(height)
    json$ + ~"}"
    
    Webdriver_Req(Cid,sessionID$+"/window/" + wHandle + "/size", json$, "",#PB_JSON_Null)
  EndIf
  
EndProcedure
Procedure Webdriver_Embedded(Cid, sessionID$, PBParent.l, noHeader = #True, disableForUser = #False)
  ;********************************************************************************
  ; PBParent parameter must be a gadgetContainer or a Window
  ; noHeader = #true will hide chromeheader (Tabs, Search bar, Bookmarks bar)
  ; disableForUser = #true to disable parent Gadget/Window
  ;********************************************************************************
  Delay(500)
  Delay(500)
  Protected width.l, height.l
  Protected oldUrl.s
  Protected dataUrl.s
  Protected PBparentHwnd
  Protected chromeTitle.s, chromeHwnd 
  Protected chromeChildTitle.s, chromeChildHwnd 
  Protected rc.rect, chromeY, chromeChildY, chromeYrelative

  oldUrl = Webdriver_GetUrl(Cid, sessionID$)
  dataUrl = URLEncoder(~"data:text/html;charset=utf-8,<!DOCTYPE HTML><title>" + sessionID$ + "</title>")
  Webdriver_Navigate(Cid, sessionID$, dataUrl)

  ;If PBParent is a containerGadget and noHeader = #true then
  ;   create a new containerGadget As child of original PBParent
  ;   and replace PBParent with the new gadget
  If noHeader = #True And IsGadget(PBParent) And GadgetType(PBParent) = #PB_GadgetType_Container
    OpenGadgetList(PBParent)
      Define PBParentNew = ContainerGadget(#PB_Any, 0,0, GadgetWidth(PBParent), GadgetHeight(PBParent), #PB_Container_BorderLess)
    CloseGadgetList()
    If IsGadget(PBParentNew)
      PBParent = PBParentNew
    EndIf
  Else
    noHeader = #False
  EndIf

  ;Resize Chrome Session to PB Parent size  
  If IsGadget(PBParent) And GadgetType(PBParent) = #PB_GadgetType_Container
    width = GadgetWidth(PBParent): height = GadgetHeight(PBParent)
    PBparentHwnd = GadgetID(PBParent)
    HideGadget(PBParent,1)
  ElseIf IsWindow(PBParent)
    width = WindowWidth(PBParent): height = WindowHeight(PBParent)
    PBparentHwnd = WindowID(PBParent)
  Else
    MessageRequester("Error!", "PBParent parameter must be a gadgetContainer or a Window", #PB_MessageRequester_Error)
    ProcedureReturn
  EndIf
  
  Webdriver_Resize(Cid, sessionID$, 1, 1)
  While WindowEvent():Wend
  
  ;Search hwnd of the chrome Window opened  
  chromeTitle      = sessionID$ + " - Google Chrome"
  chromeChildTitle = "Chrome_RenderWidgetHostHWND"
  chromeHwnd = FindWindow_(0, chromeTitle) 
  If Not chromeHwnd 
    MessageRequester("Error", chromeTitle + " must be running !") 
    End 
  Else
    chromeChildHwnd = FindWindowEx_(chromeHwnd, 0, chromeChildTitle, 0);
  EndIf   
  
  ; if noHeader = #true, we search Chrome Content part Y position and move up PB Parent Gadget/Window
  ; only works with containerGadget Parent, not when Parent is a windows
  If noHeader And chromeChildHwnd <> 0   
      GetWindowRect_(chromeHwnd,rc)
      chromeY = rc\top
      GetWindowRect_(chromeChildHwnd,rc)
      chromeChildY = rc\top               ; Y from top of screen
      chromeYrelative = chromeChildY-chromeY    ; Y from top of chrome window
      
      ResizeGadget(PBParent, #PB_Ignore, -chromeYrelative, #PB_Ignore, GadgetHeight(PBParent) + chromeYrelative)
    EndIf
    
  Webdriver_Navigate(Cid, sessionID$, oldUrl)
  While WindowEvent():Wend
  Webdriver_Resize(Cid, sessionID$, width, height+chromeYrelative)
  
  
  
  
  ; Set Chrome as child of PB Parent
  If PBparentHwnd          
    SetWindowLong_(chromeHwnd, #GWL_STYLE, GetWindowLong_(chromeHwnd, #GWL_STYLE) &(~(#WS_MAXIMIZE|#WS_SIZEBOX )))
    SetParent_(chromeHwnd, PBparentHwnd) 
    SetWindowPos_(chromeHwnd, 0, 0, 0, 0, 0, #SWP_NOSIZE|#SWP_NOZORDER|#SWP_FRAMECHANGED)           
  EndIf
 While WindowEvent():Wend
  
  If IsGadget(PBParent)
    DisableGadget(PBParent, disableForUser)
    HideGadget(PBParent,0)
  ElseIf IsWindow(PBParent)
    DisableWindow(PBParent, disableForUser)
  EndIf  
 
  
EndProcedure
;-============================
;- WD GENERAL PROCEDURES
;-============================
Procedure Webdriver_Keys(Cid, sessionID$, sKeys.s, wdDelay.l = 300)
  ;********************************************************************************
  ; Send keys to the session
  ; EXAMPLE:
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementValue(Cid, sessionID$, xpath, "Hello, world!")
  ;********************************************************************************
  Protected json$

  Delay(wdDelay)
  
  json$ =  "{" + #LF$
  json$ + ~"\"value\": [" + #DQUOTE$ + sKeys + #DQUOTE$ + "]" + #LF$
  json$ + ~"}"
  
  Webdriver_Req(Cid,sessionID$ + "/keys", json$, "",#PB_JSON_Null)
EndProcedure
Procedure.s Webdriver_GetUrl(Cid, sessionID$)
  ;********************************************************************************
  ; Retrieve the URL of the current page.
  ;********************************************************************************
  Protected url$
  url$ = Webdriver_Req(Cid,sessionID$+"/url", "", "value",#PB_JSON_String, "GET")
  ProcedureReturn(url$)
EndProcedure
Procedure.s Webdriver_Title(Cid, sessionID$)
  ;********************************************************************************
  ; Get the current page title.
  ;********************************************************************************
  Protected title$
  title$ = Webdriver_Req(Cid,sessionID$ + "/title", "", "value",#PB_JSON_String,"GET")  
  ProcedureReturn(title$)
EndProcedure
Procedure.s Webdriver_Source(Cid, sessionID$)
  ;********************************************************************************
  ; Return the source code
  ;********************************************************************************
  ProcedureReturn Webdriver_Req(Cid,sessionID$+"/source", "", "value",#PB_JSON_String,"GET")
EndProcedure
Procedure.s Webdriver_ScreenShot(Cid, sessionID$)
  ;********************************************************************************
  ; Take a screenshot of the current page.
  ; Returns string with the screenshot As a base64 encoded PNG.
  ;********************************************************************************
  Protected status.l, value.s
  status = Val(Webdriver_Req(Cid,sessionID$+"/screenshot", "", "status",#PB_JSON_Number,"GET"))
  If status = 0
    value = Webdriver_Req(Cid,sessionID$+"/screenshot", "", "value",#PB_JSON_String,"GET")
  EndIf
  
  ProcedureReturn value
EndProcedure
Procedure.s Webdriver_CookiesGetAll(Cid, sessionID$, List wdCookies.wdSTRcookie())
  ;********************************************************************************  
  ;  Retrieve all cookies visible to the current page  
  ;  Example:
  ;               NewList theCookies.wdSTRcookie()
  ;               Webdriver_CookiesGetAll(Cid, sessionID$, theCookies())
  ;               ForEach(theCookies())
  ;                 Debug theCookies()\name$
  ;                 Debug theCookies()\value$
  ;               Next  
  ;********************************************************************************
  Protected json$, jsO, jsV, objectValue.l
  
  json$ = Webdriver_Req(Cid,sessionID$+"/cookie", "", "value",#PB_JSON_Object,"GET")  
  
  jsO = ParseJSON(#PB_Any, json$)
  jsV  = JSONValue(jsO)
  objectValue = GetJSONMember(jsV, "value")
  
  ClearList(wdCookies())
  ExtractJSONList(objectValue, wdCookies())
  
EndProcedure
Procedure Webdriver_CookieAdd(Cid, sessionID$, *cookie.wdSTRcookie)
  ;********************************************************************************  
  ; Set a cookie. If the cookie path is not specified, it should be set to "/".
  ; Likewise, If the domain is omitted, it should Default To the current page's domain.  
  ; Example:
  ;             myCookie.wdSTRcookie
  ;             myCookie\name$ = "pbcookie"
  ;             myCookie\value$ = "Webdriver in PB, yeah!"
  ;             Webdriver_CookieAdd(Cid, sessionID$, myCookie)
  ;********************************************************************************
  Protected json$, status
  Protected secure.s   = "false"
  Protected httpOnly.s = "false"
  
  With *cookie
    If \httpOnly: httpOnly = "true": EndIf
    If \secure: secure = "true": EndIf
    
    json$ = ~"{"
    json$ + ~"  \"cookie\": {"    + #LF$
    json$ + ~"    \"domain\":"    + #DQUOTE$ + \domain$   + #DQUOTE$ + "," + #LF$
    json$ + ~"    \"expiry\":"    + #DQUOTE$ + \expiry    + #DQUOTE$ + "," + #LF$
    json$ + ~"    \"httpOnly\":"  + httpOnly + "," + #LF$
    json$ + ~"    \"name\":"      + #DQUOTE$ + \name$     + #DQUOTE$ + "," + #LF$
    json$ + ~"    \"path\":"      + #DQUOTE$ + \path$     + #DQUOTE$ + "," + #LF$
    json$ + ~"    \"secure\":"    + secure + "," + #LF$
    json$ + ~"    \"value\":"     + #DQUOTE$ + \value$    + #DQUOTE$ + ""
    json$ + ~"  }"
    json$ + ~"}"
    
  EndWith
  
  status = Val( Webdriver_Req(Cid,sessionID$+"/cookie", json$, "status",#PB_JSON_Number,"POST")  )
  ProcedureReturn status
  
EndProcedure

Procedure Webdriver_CookiesDelete(Cid, sessionID$, cookieName$)
  ;********************************************************************************
  ; Delete the cookie with the given name
  ;********************************************************************************
  Protected status
  status = Val (Webdriver_Req(Cid,sessionID$+"/cookie/" + cookieName$, "", "status",#PB_JSON_Number,"DELETE"))
  ProcedureReturn status
EndProcedure
Procedure.s Webdriver_CookiesDeleteAll(Cid, sessionID$)
  ;********************************************************************************
  ; Delete all cookies visible to the current page.
  ;********************************************************************************
  Webdriver_Req(Cid,sessionID$+"/cookie", "", "",#PB_JSON_Null,"DELETE")  
EndProcedure
;-============================
;- WD ELEMENTS PROCEDURES
;-============================
Procedure.s Webdriver_ElementGetID(Cid, sessionID$, xpath.s)
  ;********************************************************************************
  ; Return ID of an element
  ;********************************************************************************
  Protected json$, nJS.l, nJSv.l, ObjectValue.l, MemberKey$, MemberValue 
  Protected status, value$
  
  json$ = ~"{"
  json$ + ~"\"using\":\"xpath\","
  json$ + ~"\"value\":" + #DQUOTE$ + xpath + #DQUOTE$
  json$ + ~"}"
  
  value$ = Webdriver_Req(Cid,sessionID$ + "/element", json$, "value",#PB_JSON_Object,"POST")
  
  nJS = ParseJSON(#PB_Any, value$)
  value$ = ""
  
  If IsJSON(nJS)  
    nJSv = JSONValue(nJS)
    If nJSv
      Select wdBrowser
        Case  "chrome"
          status = GetJSONInteger(GetJSONMember(nJSv, "status"))
          If status = 0
            value$ = GetJSONString(GetJSONMember(GetJSONMember(nJSv, "value"), "ELEMENT"))
          EndIf
        Case "firefox"
          ObjectValue = GetJSONMember(nJSv, "value")
          If ObjectValue
            MemberKey$ = JSONMemberKey(ObjectValue)
            MemberValue = JSONMemberValue(ObjectValue)
            If MemberValue
              value$ = GetJSONString(MemberValue)
            EndIf
          EndIf
      EndSelect
    EndIf  
  EndIf
  
  ProcedureReturn value$
EndProcedure
Procedure Webdriver_ElementClick(Cid, sessionID$, xpath.s, wdDelay.l = 300)
  ;********************************************************************************
  ; Click in element
  ; EXAMPLE:   
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementClick(Cid, sessionID$, xpath) 
  ;********************************************************************************
  Protected elementoID.s, sScript.s, args.s
  
  Delay(wdDelay)  
  
  elementoID = Webdriver_ElementGetID(Cid, sessionID$, xpath)
  
  Select wdBrowser
    Case "chrome"      
      Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/click", "", "",#PB_JSON_Null,"POST")  
    Case "firefox"     
      xpath = URLEncoder(xpath)
      sScript = "arguments[0].click();"      
      args = ~"{\"ELEMENT\":" + #DQUOTE$ + elementoID + #DQUOTE$ + "}"      
      Webdriver_Execute(Cid, sessionID$, sScript, args)
  EndSelect
  
EndProcedure
Procedure Webdriver_ElementValue(Cid, sessionID$, xpath.s, sKeys.s, wdDelay.l = 300)
  ;********************************************************************************
  ; Type text in an element
  ; EXAMPLE:
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementValue(Cid, sessionID$, xpath, "Hello, world!")
  ;********************************************************************************
  Protected json$, elementoID.s
    
  Delay(wdDelay)
  
  elementoID = Webdriver_ElementGetID(Cid, sessionID$, xpath)  
  
  json$ =  "{" + #LF$
  json$ + ~"\"value\": [" + #DQUOTE$ + sKeys + #DQUOTE$ + "]" + #LF$
  json$ + ~"}"
  
  Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/value", json$, "",#PB_JSON_Null)
EndProcedure
Procedure.s Webdriver_ElementGetText(Cid, sessionID$, xpath.s, wdDelay.l = 500)
  ;********************************************************************************
  ; Get text in an element
  ; EXAMPLE:
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementValue(Cid, sessionID$, xpath, "Hello, world!")
  ;********************************************************************************
  Protected elementoID.s
  Protected status, value$
  
  Delay(wdDelay)
  
  status = 0
  value$  = ""
  
  elementoID = Webdriver_ElementGetID(Cid, sessionID$, xpath)  
  
  If elementoID
    status = Val( Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/text", "", "status",#PB_JSON_Number, "GET") )
    If status = 0 ; OK?
      value$ = Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/text", "", "value",#PB_JSON_String, "GET")
    EndIf
  EndIf
    
  ProcedureReturn value$
  
EndProcedure
Procedure Webdriver_ElementClear(Cid, sessionID$, xpath.s, wdDelay.l = 300)
  ;********************************************************************************
  ; Clear visible text in textarea or other element
  ; EXAMPLE:   
  ;           xpath = "/html/body/div[1]/div[1]/div[1]/div[1]/div[2]/textarea"
  ;           Webdriver_ElementClear(Cid, sessionID$, xpath) 
  ;********************************************************************************
  Protected elementoID.s
  
  Delay(wdDelay)  
  
  elementoID = Webdriver_ElementGetID(Cid, sessionID$, xpath)   
  Webdriver_Req(Cid,sessionID$ + ~"/element/" + elementoID + "/clear", "", "",#PB_JSON_Null,"POST")  
EndProcedure
;-============================
;- WD SCRIPTS PROCEDURES
;-============================
Procedure.s Webdriver_Execute(Cid, sessionID$, sScript.s, arguments$, sAsync.b = #False)
  ;********************************************************************************
  ; Execute an script sync or async, depending of sAsync var value
  ; EXAMPLE:
  ;         Webdriver_Execute(Cid,sessionID$, "alert('hello');")
  ;         devuelve STATUS|MESSAGE
  ;********************************************************************************
  Protected json$, res$, nJS.l, Async$, status, message.s
  
  Select wdBrowser
    Case "chrome"
      If sAsync: Async$ = "_async": Else: Async$ = "": EndIf
    Case "firefox"
      If sAsync: Async$ = "/async": Else: Async$ = "/sync": EndIf
  EndSelect
  
  json$ = ~"{" + #LF$
  json$ + ~"\"script\": " + #DQUOTE$ + sScript + #DQUOTE$ + #LF$
  json$ + ~", \"args\": [" + arguments$ + "]" + #LF$  
  json$ + ~"}" + #LF$      
  res$ = Webdriver_Req(Cid, sessionID$ + "/execute" + Async$, json$, "", #PB_JSON_Object)
  
  Select wdBrowser
    Case "chrome"      
      nJS = ParseJSON(#PB_Any, res$)
      If IsJSON(nJS)
        nJS = JSONValue(nJS)
        status = GetJSONInteger(GetJSONMember(nJS, "status"))
        If status = 0
          message = "OK"
        Else      
          message = GetJSONString(GetJSONMember(GetJSONMember(nJS, "value"), "message"))
        EndIf      
        res$ = Str(status) + "|" + message    
      EndIf
    Case "firefox"
      res$ = "0|0"
  EndSelect
  
  
  ProcedureReturn res$
  
EndProcedure
;-============================
;- WEBDRIVER FIREFOX EXAMPLE
;-============================
CompilerIf #PB_Compiler_IsMainFile 
  DisableExplicit
  
  ;global variable wdBrowser must be defined before all other commands (by default, wdBrowser = "chrome"
  wdBrowser = "firefox"
  
  default_driver_Port = 4444
  driver_location$ = "geckodriver.exe"
  Wbid = RunProgram(driver_location$ ,"-v" ,"",#PB_Program_Open)

 
  Cid = OpenNetworkConnection("127.0.0.1",default_driver_Port)
  
  Webdriver_DesiredCapabilitiesAdd("default", "default")
  Webdriver_DesiredCapabilitiesAdd("binary", #DQUOTE$ + "d:/FirefoxPortable_63.0_English.paf/App/Firefox64/firefox.exe"+#DQUOTE$)
;   Webdriver_DesiredCapabilitiesAdd("marionette", "true")
;   Webdriver_DesiredCapabilitiesAdd("goog:chromeOptions", ~"{\"w3c\": true}")

  
  sessionID$  = "/session/" + Webdriver_NewSession(Cid, "")
  
  Webdriver_Navigate(Cid, sessionID$, "https://www.purebasic.fr/english/")
  
  xpath.s = "//*[@id='menubar']/table/tbody/tr/td[1]/a[2]"
  Webdriver_ElementClick(Cid, sessionID$, xpath)
  
  Delay(2000)
  Webdriver_Execute(Cid,sessionID$, "alert('hello, PB user');", "")
  
  Delay(5000)
  Webdriver_DeleteSession(Cid, sessionID$)
  CloseNetworkConnection(Cid)
  KillProgram(Wbid)
  CloseProgram(Wbid)  
  Delay(1000)
CompilerEndIf


;-============================
;- WEBDRIVER CHROME EXAMPLE 1
;-============================
CompilerIf #PB_Compiler_IsMainFile 
  DisableExplicit
  
  ;global variable wdBrowser must be defined before all other commands (by default, wdBrowser = "chrome"
  wdBrowser = "chrome"
  
  default_driver_Port = 9515
  driver_location$ = "chromedriver.exe"
  Wbid = RunProgram(driver_location$ ,"" ,"",#PB_Program_Open)
  
  Cid = OpenNetworkConnection("127.0.0.1",default_driver_Port)
  
  Webdriver_DesiredCapabilitiesAdd("default", "default")
  ClearList(chromeOptions())
  Webdriver_ChromeOptionsAdd("--window-size", "800,700")  
  sessionID$  = "/session/" + Webdriver_NewSession(Cid, "")
  
  Webdriver_Navigate(Cid, sessionID$, "https://www.purebasic.fr/english/")
  
  xpath.s = "//*[@id='menubar']/table/tbody/tr/td[1]/a[2]"
  Webdriver_ElementClick(Cid, sessionID$, xpath)
  
  xpath.s = "//*[@id='pagecontent']/form/table/tbody/tr[2]/td[2]/input[1]"
  Webdriver_ElementValue(Cid, sessionID$, xpath, "Chromedriver")
  Webdriver_ElementValue(Cid, sessionID$, xpath, "\n")
  
  
  Delay(2000)
  Webdriver_DeleteSession(Cid, sessionID$)
  CloseNetworkConnection(Cid)
  KillProgram(Wbid)
  CloseProgram(Wbid)  
  Delay(1000)
CompilerEndIf


;-============================
;- WEBDRIVER CHROME EMBEDDED EXAMPLE
;-============================
CompilerIf #PB_Compiler_IsMainFile 
  
  DisableExplicit
  
  ;global variable wdBrowser must be defined before all other commands (by default, wdBrowser = "chrome"
  wdBrowser = "chrome"
    
  ;Create a window with a container
  mainWindow = OpenWindow(#PB_Any, 0, 0, 800, 600, "PB WINDOWS with a containerGadget", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget) 
  containerG = ContainerGadget(#PB_Any, 50,50, 700,500, #PB_Container_BorderLess)  
  CloseGadgetList()  
  SetGadgetColor(containerG, #PB_Gadget_BackColor, $BFBF3F)
  While WindowEvent(): Wend  
  
  default_driver_Port = 9515
  Wbid = RunProgram(driver_location$ ,"" ,"",#PB_Program_Open|#PB_Program_Hide)
    
  Cid = OpenNetworkConnection("127.0.0.1",default_driver_Port)
  
  Webdriver_DesiredCapabilitiesAdd("default", "default")
  ClearList(chromeOptions())
  Webdriver_ChromeOptionsAdd("--window-size", "100,100")
  Webdriver_ChromeOptionsAdd("--window-position", "-1000,-1000")
  
  sessionID$  = "/session/" + Webdriver_NewSession(Cid, "")
  
  
  Webdriver_Embedded(Cid, sessionID$, containerG, #True)
  
  Webdriver_Navigate(Cid, sessionID$, "https://www.purebasic.fr/english/")
  
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
  
  Debug "Delete: " + Webdriver_DeleteSession(Cid, sessionID$)
  
  CloseNetworkConnection(Cid)
  KillProgram(Wbid)
  CloseProgram(Wbid)
  
CompilerEndIf
[/size]


I will try to make this code Gecko compatible, but it a hard work because documentation is scarce and confusing to me.
Last edited by zikitrake on Thu Nov 01, 2018 9:32 am, edited 1 time in total.
Post Reply