Jump to content
Sign in to follow this  
XinYoung

Trouble With my Loop Using Excel & IE

Recommended Posts

Hello all,

Preface: Column A is full of courses. Column B is full of usernames. If course (A1) exists, we check to see if username (B1) is enrolled. If user is found, the user is un-enrolled. Then Loop.

I am working on a script that loops through an Excel file and pastes the content from A1 into a textbox in IE, does some stuff, then pastes the content from B1 into a different textbox. Then it loops around until all used rows in columns A and B have been accounted for.

For some reason, column A loops properly but column B doesn't. B1 is pasted over and over again. So, as it loops, B1 is constantly being pasted, first accompanying A1's loop, then A2, and so on.

  • The OpenExcel() func opens the Excel file the user specifies in an earlier function. It's supposed to gather the entire used range of columns A and B.
  • The SearchCourse() func only uses column A, pasting its content into a Search tool in IE. This seems to be working fine.
  • SearchResult() puts "Course Not Found" into column C if the search fails. If the search is successful, however, we move onto...
  • EnterCourse(). This simply gets us to the place where column B's content comes into play.
  • UnenrollNow(). Here, we paste the variable $_userName into a textbox. I don't know why it's always B1 :frantics:
Func OpenExcel()
    If Not WinExists($hWnd) Then
        MsgBox(16, "Window closed", "The Internet Explorer window was closed. Please start over.")
        _Exit()
    Else
        $oExcel = _Excel_Open()
        Global $oWorkbook = _Excel_BookOpen($oExcel, $ChosenFileName, Default, True, True)
        $oExcel.Sheets("CopyCourses").Activate
;~ Get all used cells in columns A and B
        $aSearchItems = _Excel_RangeRead($oWorkbook, 1, $oWorkbook.Sheets("CopyCourses").Usedrange.Columns("A:B"))
;~ Create the $aSearchResult array
        ReDim $aSearchResult[UBound($aSearchItems)]
;~ Loop through the array starting at 0 until the end of the array which is (Ubound($aSearchItems) - 1)
        For $i = 0 To UBound($aSearchItems) - 1
;~ Column 0
            ConsoleWrite($aSearchItems[$i][0] & @CRLF)
;~ Column 1
            ConsoleWrite($aSearchItems[$i][1] & @CRLF)
            $aSearchResult[$i] = SearchCourse($aSearchItems[$i][0], $aSearchItems[$i][1])
        Next
        _Excel_RangeWrite($oWorkbook, Default, $aSearchResult, "C1")
;~ When the loop is complete, run the Finished function.
        Finished()
    EndIf
EndFunc   ;==>OpenExcel

Func SearchCourse($_sSearchResult, $_userName)
    If Not WinExists($hWnd) Then
        MsgBox(16, "Window closed", "The Internet Explorer window was closed. Please start over.")
        _Exit()
    Else
        _IENavigate($oIE, $urlBBCourseSearch)
        _IELoadWait($oIE)
        Local $oForm = _IEGetObjByName($oIE, "courseManagerFormSearch")
        Local $oSearchString = _IEFormElementGetObjByName($oForm, "courseInfoSearchText")
        _IEFormElementSetValue($oSearchString, $_sSearchResult)
        _IEFormSubmit($oForm)
        _IELoadWait($oIE)
        Local $oBBTable = _IETableGetCollection($oIE, 2)
        $aBBTableData = _IETableWriteToArray($oBBTable)
        Return SearchResult()
    EndIf
EndFunc   ;==>SearchCourse

Func SearchResult()
    If Not WinExists($hWnd) Then
        MsgBox(16, "Window closed", "The Internet Explorer window was closed. Please start over.")
        _Exit()
    Else
        Local $sResult
        $iSearchIndex = _ArraySearch($aBBTableData, "Course ID", 0, 0, 0, 1, 1, 0)
        If $iSearchIndex = -1 Then
            $sResult = "Course Not Found"
            _Excel_RangeWrite($oWorkbook, Default, $aSearchResult, "C1")
        Else
            EnterCourse()
            $sResult = "UnEnrolled!"
            _Excel_RangeWrite($oWorkbook, Default, $aSearchResult, "C1")
        EndIf
        Return $sResult
    EndIf
EndFunc   ;==>SearchResult

Func EnterCourse()
    If Not WinExists($hWnd) Then
        MsgBox(16, "Window closed", "The Internet Explorer window was closed. Please start over.")
        _Exit()
    Else
        Local $clickFail = "DATE CREATED"
        _IELinkClickByIndex($oIE, 34)
        _IELoadWait($oIE)
        $sourceCode = _IEBodyReadHTML($oIE)
        If StringInStr($sourceCode, $clickFail) <> 0 Then
            _IELinkClickByIndex($oIE, 35)
            _IELoadWait($oIE)
        EndIf
        $oLink = _IEGetObjById($oIE, "controlpanel.users.and.groups_groupExpanderLink")
        _IEAction($oLink, "click")
        Sleep(500)
        _IELinkClickByText($oIE, "Users")
        _IELoadWait($oIE)
        $aSearchResult[$i] = UnenrollNow($aSearchItems[$i][0], $aSearchItems[$i][1])
    EndIf
EndFunc   ;==>EnterCourse

Func UnenrollNow($_sourceCourseId, $_userName)
    If Not WinExists($hWnd) Then
        MsgBox(16, "Window closed", "The Internet Explorer window was closed. Please start over.")
        _Exit()
    Else
        Local $UserError = "No users found"
        Local $sResult
        $criteriaUsername = _IEGetObjById($oIE, "userInfoSearchKeyString")
        _IEFormElementOptionSelect($criteriaUsername, 0, 1, 'byIndex')
        $criteriaUsername = _IEGetObjById($oIE, "userInfoSearchOperatorString")
        _IEFormElementOptionSelect($criteriaUsername, 0, 1, 'byIndex')

        ;Paste whats copied from column B into the Username text box.
        Local $oForm = _IEGetObjByName($oIE, "userManagerSearchForm")
        Local $oSearchString = _IEFormElementGetObjByName($oForm, "userInfoSearchText")
        
        ;PROBLEM HERE...
        
        _IEFormElementSetValue($oSearchString, $_userName)
        
        ;^^^^^^ WHY IS $_userName ALWAYS B1 ???
        
        Sleep(1000)
        _IEFormSubmit($oForm)
        _IELoadWait($oIE)

        $sourceCode = _IEBodyReadHTML($oIE)
        If StringInStr($sourceCode, $UserError) <> 0 Then
            $sResult = "User Not Found"
            _Excel_RangeWrite($oWorkbook, Default, $aSearchResult, "C1")
            Return $sResult
        Else
            MsgBox(0, "Unenrollment READY!", "We're ready to unenroll foreal")
            $sResult = "DUN"
            _Excel_RangeWrite($oWorkbook, Default, $aSearchResult, "C1")
            Return $sResult
        EndIf
    EndIf
EndFunc   ;==>UnenrollNow

Please let me know if any further information is needed.

If you see other problems or redundancies in my code, please let me know.

Thank you!

 

Edited by XinYoung

Share this post


Link to post
Share on other sites

Hard to say just looking at this code, since we don't have access to your web site.  Do I understand right, that the problem is in IE when you set the value ?  Could you show a screen of the problem with the associated DOM ?

Share this post


Link to post
Share on other sites

Sure. Here's the DOM for the inputbox that requires the values from column B in my Excel sheet.

I don't think there's a problem with how I'm manipulating IE though. I think I'm storing the Excel content wrong or looping through Excel wrong.

image.thumb.png.4fcfe0bb900c59665f237ef8804cc251.png

Share this post


Link to post
Share on other sites
$aSearchResult[$i] = UnenrollNow($aSearchItems[$i][0], $aSearchItems[$i][1])

$i is undefined in Func EnterCourse(), I don't even understand how you don't get an error

Share this post


Link to post
Share on other sites
1 hour ago, XinYoung said:

i declare it globally at the beginning of the script...

Remove that, it doesn't make any sense, make your script robust, Any variables inside of a func should come local or from param.  I understand that sometimes, you need to have global vars, but if you want to solve your problems, you should start reducing the bad programming habits.  Sorry from being rude...

ps : Also use : Opt ("MustDeclareVars, 1) at the very beginning of your script.

Edited by Nine

Share this post


Link to post
Share on other sites

OK... You're not rude lol

So, for best practice. how/where should I implement the $i within the EnterCourse() func?

Func EnterCourse()
    If Not WinExists($hWnd) Then
        MsgBox(16, "Window closed", "The Internet Explorer window was closed. Please start over.")
        _Exit()
    Else
        Local $clickFail = "DATE CREATED"
        _IELinkClickByIndex($oIE, 34)
        _IELoadWait($oIE)
        $sourceCode = _IEBodyReadHTML($oIE)
        If StringInStr($sourceCode, $clickFail) <> 0 Then
            _IELinkClickByIndex($oIE, 35)
            _IELoadWait($oIE)
        EndIf
        $oLink = _IEGetObjById($oIE, "controlpanel.users.and.groups_groupExpanderLink")
        _IEAction($oLink, "click")
        Sleep(500)
        _IELinkClickByText($oIE, "Users")
        _IELoadWait($oIE)
        $aSearchResult[$i] = UnenrollNow($aSearchItems[$i][0], $aSearchItems[$i][1])
        
        ;WARNING: $i: possibly used before declaration.
        
    EndIf
EndFunc   ;==>EnterCourse

 

Share this post


Link to post
Share on other sites
45 minutes ago, XinYoung said:

Do i just throw it in as a local declaration at the beginning?

No, $i comes from another func.  But it is not your only problem.  Lets just take EnterCourse func. 

$hWnd, $oIE, $sourceCode, $aSearchResult, $aSearchItems and $i have all been declared as global vars.  That is really not good. 

$i for example comes from a For loop.  If you read carefully help file, it says that "The variable will be created automatically with Local scope, even when MustDeclareVars is on."  So $i has been declare local in another func.  You cannot access it even if you declare local or global or whatever. Those few functions that you have posted at the beginning needs to be rethink with the best practices :  All vars should be declared locally or passed as function parameters.  If you do that you probably won't have the same number of functions, probably less.
 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By FUD
      hello 
      please i need help 
      i need to open link in default browser only one windows without duplicate if i try to open the same link 
       
      thanks 
    • By GOSM
      Hey,
      as part of a larger Programm I am trying to copy the values from one cell in an Excel file to another. The code I am using is the folowing.
       
      Local $oExcel = _Excel_Open() If @error Then Exit MsgBox($MB_SYSTEMMODAL, "Excel UDF: _Excel_RangeCopy Example", "Error creating the Excel application object." & @CRLF & "@error = " & @error & ", @extended = " & @extended) _Excel_RangeCopyPaste($oExcel.ActiveSheet, "V4:W43", "X4", False, $xlPasteValues, Default, True) If @error Then Exit MsgBox($MB_SYSTEMMODAL, "Excel UDF: _Excel_RangeCopy Example 4", "Error copying rows." & @CRLF & "@error = " & @error & ", @extended = " & @extended) MsgBox($MB_SYSTEMMODAL, "Excel UDF: _Excel_RangeCopy Example 4", "2 Rows successfully pasted from the clipboard to row 1.") As I understood it the option $xlPasteValues should do the trick  but it is still copying the inserted formulas. I attached a test code and excel file.
      Thanks for the help Simon
      Copy Values Test.zip
    • By Chimp
      An "improper" "unusual" use of Excel
      the script allows the creation of artistic images by simply coloring the background of the individual cells of the Excel workbook.
      Although definitely useless ... I find it quite funny though
      have a good time
      many thanks to @UEZ , @Malkey , @water
      p.s.
      I think the pixelite + color to array process can be simplified, but I used the two ready-made functions provided by UEZ and Malkey. I thank both of you (credits  and links in listing)
      p.p.s.
      strange behaviour: while excell is filling cells, if you move the mouse pointer off the excell window, the fill speed increases ... (?)

       
      ; =============================================================================================================================== ; Name ..........: Excel in art ; Description ...: This script allows the creation of artistic images in Excel from a choosed picture. ; The picture is done by simply coloring the background of the individual cells of an Excel workbook. ; Although definitely useless, I find it quite funny though ; ; Return values .: An artistic image in an Excel workbook ; Author ........: Addiego Gianni (chimp) ; Modified ......: ; Remarks .......: Many thanks to UEZ, Malkey and Water ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== #include <GDIPlus.au3> #include <Excel.au3> _PixelsToCells(50) ; <-- Parameter 50 is the cumber of horizontal Excel cells to be filled MsgBox(64, "All done", "Excel art is ready") Func _PixelsToCells($iHcells = 50) ; Check application object Local $oExcel = _Excel_Open() If Not IsObj($oExcel) Then MsgBox(16, "Error", "Sorry, You need to have 'Excel' intalled") ; Choose Image File Local $sPath = FileOpenDialog("Choose Image File", @ScriptDir & "", "Images (*.gif;*.png;*.jpg;*.bmp)| All (*.*)") If $sPath = '' Then Exit MsgBox(16, "Error", "Sorry, no image was chosen") ; Create a new Excel workbook $oWorkbook = _Excel_BookNew($oExcel, 1) ; initialize GDI+ _GDIPlus_Startup() Local $hBmp = _GDIPlus_BitmapCreateFromFile($sPath) Local $iWidth = _GDIPlus_ImageGetWidth($hBmp) ; get image width ; Local $iHeight = _GDIPlus_ImageGetHeight($hBmp) ; not needed here Local $iStep = $iWidth / $iHcells ; calculate the pixelation factor Local $hBitmap_new = _GDIPlus_PixelateBitmap($hBmp, $iStep) ; pixelate the image Local $aPixelColors = _FileImageToArray($hBitmap_new) ; get pixel colors ; reduce Excel columns width Local $xx = 1, $yy = 1 For $iCol = 0 To UBound($aPixelColors, 2) - 1 Step $iStep $oWorkbook.Sheets(1).Columns($xx).ColumnWidth = 1 $xx += 1 Next ; reduce Excel rows height For $iRow = 0 To UBound($aPixelColors) - 1 Step $iStep $oWorkbook.Sheets(1).Rows($yy).RowHeight = 9 $yy += 1 Next $xx = 1 $yy = 1 For $iRow = 0 To UBound($aPixelColors) - 1 Step $iStep For $iCol = 0 To UBound($aPixelColors, 2) - 1 Step $iStep $oWorkbook.Sheets(1).Range(_Excel_ColumnToLetter($xx) & $yy).Interior.Color = Number("0x" & $aPixelColors[$iRow][$iCol]) $xx += 1 Next $yy += 1 $xx = 1 Next _GDIPlus_BitmapDispose($hBmp) _GDIPlus_Shutdown() EndFunc ;==>_PixelsToCells ; by UEZ ; https://www.autoitscript.com/forum/topic/167707-imagepixelate/?do=findComment&comment=1227509 Func _GDIPlus_PixelateBitmap($hBitmap, $iPixelate, $bSmooth = 1) Local $iWidth = _GDIPlus_ImageGetWidth($hBitmap), $iHeight = _GDIPlus_ImageGetHeight($hBitmap) Local $iNewW = Round($iWidth / $iPixelate, 0), $iNewH = Round($iHeight / $iPixelate, 0) Local $hBitmap_scaled = _GDIPlus_BitmapCreateFromScan0($iNewW, $iNewH) Local $hCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap_scaled) Local $iInterpolation = 5 If $bSmooth Then $iInterpolation = $GDIP_INTERPOLATIONMODE_BILINEAR _GDIPlus_GraphicsSetInterpolationMode($hCtxt, $iInterpolation) _GDIPlus_GraphicsDrawImageRect($hCtxt, $hBitmap, 0, 0, $iNewW, $iNewH) _GDIPlus_GraphicsDispose($hCtxt) Local $hBitmap_pixelated = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) $hCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap_pixelated) _GDIPlus_GraphicsSetInterpolationMode($hCtxt, $GDIP_INTERPOLATIONMODE_NearestNeighbor) _GDIPlus_GraphicsDrawImageRectRect($hCtxt, $hBitmap_scaled, 0, 0, $iNewW, $iNewH, -$iPixelate, -$iPixelate, $iWidth + 2 * $iPixelate, $iHeight + 2 * $iPixelate) _GDIPlus_GraphicsDispose($hCtxt) Return $hBitmap_pixelated EndFunc ;==>_GDIPlus_PixelateBitmap ; by Malkey ; https://www.autoitscript.com/forum/topic/112540-is-there-a-function-for-reading-images-into-2d-arrays/?do=findComment&comment=788472 Func _FileImageToArray($hImage) Local $Reslt, $stride, $format, $Scan0, $iIW, $iIH ; , $hImage Local $v_Buffer, $width, $height ; _GDIPlus_Startup() ; $hImage = _GDIPlus_ImageLoadFromFile($sFileName) $iIW = _GDIPlus_ImageGetWidth($hImage) $iIH = _GDIPlus_ImageGetHeight($hImage) ProgressOn("Progress Bar", "Filling a " & $iIW & " x " & $iIH & " size array.", "0 percent") $Reslt = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iIW, $iIH, $GDIP_ILMREAD, $GDIP_PXF32ARGB) ;Get the returned values of _GDIPlus_BitmapLockBits () $width = DllStructGetData($Reslt, "width") $height = DllStructGetData($Reslt, "height") $stride = DllStructGetData($Reslt, "stride") $format = DllStructGetData($Reslt, "format") $Scan0 = DllStructGetData($Reslt, "Scan0") Local $aArray[$height][$width] For $j = 0 To $iIH - 1 For $i = 0 To $iIW - 1 $v_Buffer = DllStructCreate("dword", $Scan0 + ($j * $stride) + ($i * 4)) $aArray[$j][$i] = StringRegExpReplace(Hex(DllStructGetData($v_Buffer, 1), 6), "(.{2})(.{2})(.{2})", "\3\2\1") ; To RGB format Next ProgressSet(Int(100 * $j / ($iIH)), Int(100 * $j / ($iIH)) & " percent") Next _GDIPlus_BitmapUnlockBits($hImage, $Reslt) ProgressOff() _GDIPlus_ImageDispose($hImage) Return $aArray EndFunc ;==>_FileImageToArray  
    • By Mariog2000
      I've tried for a few days to simply open a url in IE and click an IE object that I can't "TAB" to and don't want to use a mouse-click if at all possible.  I've read up on things like using IEAction and IETagNameGetCollection to find the object but not smart enough to figure out how that works with my url or how to tell if my url is "basic" or a "form", "frameset", "iframe", etc.
      The other problem is I've tried using the "Run" and "ShellExecute" commands to open the browser, which works, but it opens it in a way that doesn't include my currently logged in user account.  For example, if I just click IE or Chrome for that matter and open my default homepage of google, the page that opens knows I'm logged in.  When I use "Send" "ShellExecute" or "_IE_Create" they always open pages generically which would require a login.
      So questions are, if I have a URL I'm trying to open, that's passes the currently logged on users credentials when opening the page (no clue where that happens)
      1.  Are there any code examples someone is willing to share that opens my IE maximized, with logged in credentials, and
      2.  Once that works, can someone suggest a technique a non-developer can find which IE Objects I need to send a "click" to so it opens the correct menu, pop-up, url, etc., associated with that object.  I've copied what doesn't work and sure I'm way off but it's not for a lack of effort. I'll keep trying and post updates but not looking good 🙂
      #include <IE.au3>
      Call ("selection")
      Func selection ()
      Global $oIE = _IECreate ("https://internal-webpage.aspx")
      Local $selectid = _IEGetObjByName ($oIE, "signageNo")
      Local $button = _IEGetObjByName ($oIE, "GO")

      _IEFormElementOptionSelect ($selectid, "3")
      _IEAction ($button,"click")
      EndFunc
      #include <IE.au3> Call ("selection") Func selection () Global $oIE = _IECreate ("https://internal-webpage.aspx") Local $selectid = _IEGetObjByName ($oIE, "signageNo") Local $button = _IEGetObjByName ($oIE, "GO") _IEFormElementOptionSelect ($selectid, "3") _IEAction ($button,"click") EndFunc 1. 
    • By singh54
      Hello All,

      I am new to auto It  and coding. Have only tried few automated logging for different websites.  The login pages of the websites which I have worked on were having form name with input type as text and it seems straight forward to automate their login using "_IEFormElementSetValue".
      I have got a url, it does not have any form in the source page. On further analyzing I found that It does call some login page separately as below.
      function showLogin(arg) {
        Global.pollingDialogDoc = null;
        var fresh = jQuery.isValidString(arg) && "fresh" == arg ? !0 : !1, appFrame = $("#appFrame");
        if ($("#modalFrame").show(), $("iframe").hide(), fresh || !appFrame.attr('src').match("html/login.html")) appFrame.attr('src', baseURL + 'html/login.html'), 
        appFrame.on('load', function() {
          setTimeout(function() {
            $("#modalFrame").hide(), appFrame.show();
          }, 1);
        }); else try {
          window.frames.appFrame.updatePageFromIndex();
        } catch (e) {}
      }
      I can simply use "send" and "mouse click" Method to automate the login but that doesn't seems very reliable. Is there any separate way to fill the user ID and password to the respective fields by having reference by frames or something. 
      Appreciate if any one can point me to correct document or help in any way...!
×
×
  • Create New...