728x90
반응형

기존에 제대로 컴파일되던 것이  오래조래 쪼물닥거리다가, 이제 컴파일도 되지 않는다.

궁극적인 목적은 리눅스에서 오류가 발생해서 해결하고자 하는 것이다.

 

코드를 이래저래 수정하다가, 제대로 되던 Local환경인 Windows OS에서 아래의 오류 메시지가 발생했다.

개발도구에서는 1줄짜리의 Warn 메시지를 출력하여, 문맥에 따라 개행을 해 보았다.

 

결론은 쭉 가다라,  ChromeDriver버전과 Chrome Browser버전이 호환이 안된다는 것이다.

( 만약  Chrome Browser가 자동으로 스스로 업데이트하면, 문제를 유발할 수 있다. 제대로 되던 것이 안될 수 있다.)

 

[2024-11-19 11:06:24.475] [WARN ] [main] org.springframework.web.context.support.GenericWebApplicationContext Exception encountered during context initialization - 
cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webbizApplication': 
Unsatisfied dependency expressed through field 'webCrawlExecutor'; 
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'webCrawlExecutor' defined in file [D:\ProgramLang\cardatabase\target\classes\kr\pe\speech\webbiz\service\WebCrawlExecutor.class]: 
Unsatisfied dependency expressed through constructor parameter 0; 
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'webCrawlService': 
Invocation of init method failed; 
nested exception is org.openqa.selenium.SessionNotCreatedException: 
Could not start a new session. 
Response code 500. Message: session not created: 
This version of ChromeDriver only supports Chrome version 129

Current browser version is 131.0.6778.70 with binary path C:\Program Files\Google\Chrome\Application\chrome.exe 
Host info: host: 'DESKTOP-624R5NN', ip: '192.168.50.50'
Build info: version: '4.10.0', revision: 'c14d967899'
System info: os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '17.0.9'
Driver info: org.openqa.selenium.chrome.ChromeDriver

 

여차저차 결론은 ChromeDriver 4.10.0은  Chrome Brower 129.x.x.x만을 지원한다는 것 같다.

 

 

아래는 Dev 서버 환경인 Linux 서버에서의 오류 메시지이다.

 

[2024-11-19 17:34:54.050] [WARN ] [main] org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext Exception encountered during context initialization - 
cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webbizApplication': 
Unsatisfied dependency expressed through field 'webCrawlExecutor'; 
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'webCrawlExecutor' defined in URL [jar:file:/root/backend/webbiz-0.3.0-SNAPSHOT.jar!/BOOT-INF/classes!/kr/pe/speech/webbiz/service/WebCrawlExecutor.class]: 
Unsatisfied dependency expressed through constructor parameter 0; 
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'webCrawlService': 
Invocation of init method failed; 
nested exception is org.openqa.selenium.SessionNotCreatedException: 
Could not start a new session. 
Possible causes are invalid address of the remote server or browser start-up failure.
Host info: host: 'springboot2', ip: '10.0.0.17'

 

 

chrome을 설치한다.

google-chrome-stable_current_x86_64.rpm

 

 

Error: Package: google-chrome-stable-131.0.6778.69-1.x86_64 (/google-chrome-stable_current_x86_64)
           Requires: libc.so.6(GLIBC_2.18)(64bit)
Error: Package: google-chrome-stable-131.0.6778.69-1.x86_64 (/google-chrome-stable_current_x86_64)
           Requires: libc.so.6(GLIBC_2.25)(64bit)
 You could try using --skip-broken to work around the problem

 

 

 

 

 libc.so.6(GLIBC_2.25) 를 직접 빌드 등을 통해서, 기존의 OS에 업데이트 하는 것은 상당히 위험하니 수행하지 않아야 한다.  심볼릭링크를 치환하거니 LD_LIBRARY_PATH 등을 통해 수행하면 오류가 발생하고, 그 이후부터는 OS의 명령어가 제대로 동작하지 않을 수 있다.  그럼. OS를 재설치하여야 한다.!!!

 

 

그래서, 해결책은 최신의 크롬이나 크롬드라이버이므로  OS를 업데이트했다. 

그러니 제대로 동작하는 것 같다. 

 

[2024-11-21 11:31:38.641] [INFO ] [main] org.openqa.selenium.remote.service.DriverService Driver logs no longer sent to console by default; https://www.selenium.dev/documentation/webdriver/drivers/service/#setting-log-output
[2024-11-21 11:31:40.167] [WARN ] [main] org.openqa.selenium.devtools.CdpVersionFinder Unable to find CDP implementation matching 131
[2024-11-21 11:31:40.168] [WARN ] [main] org.openqa.selenium.chromium.ChromiumDriver Unable to find version of CDP to use for . You may need to include a dependency on a specific version of the CDP using something similar to `org.seleniumhq.selenium:selenium-devtools-v86:4.10.0` where the version ("v86") matches the version of the chromium-based browser you're using and the version number of the artifact is the same as Selenium's.

 

다만,  JAVA 내의  selenium  종속성의 버전도 업데이트해 줄 필요성도 있어 보인다. 

 

728x90
반응형
728x90
반응형

특정 웹사이트에 존재하는 하이퍼링크 갯수 및  특정 하이퍼링크 아래에 존재하는 또 다른 하이퍼링크의 갯수 즉 3단계 레벨까지의 총 하이퍼링크 갯수를 알아내고자 프로그램을 하는데, 약 3-4시간 투입했지만 제대로 안된다. 배경 지식을 좀 더 쌓은 후에 다시 진입하여야 하여, 구글링한 자료를 아래와 같이 정리해 봅니다.

 

 

탭 관련해서는 생성과 포커스(이동) 및  해당 탭에서 자료 출력...을 하여야 합니다.

핸들의 개념이 있고요.  List 등에서는  Last(), First() 등이 이미 있습니다.

//탭 생성
((IJavaScriptExecutor)_driver).ExecuteScript("window.open();");


//마지막 탭으로 이동.
_driver.SwitchTo().Window(_driver.WindowHandles.Last());
 
//첫 탭으로 이동.
_driver.SwitchTo().Window(_driver.WindowHandles.First());
 
//특정 탭 저장 후 이동.
string winHandleBefore = _driver.CurrentWindowHandle;
_driver.SwitchTo().Window(winHandleBefore);

//현재 탭 닫기.
_driver.Close();

//최대화 하기
driver.Manage().Window.Maximize();

 

stale element reference element is not attached to the page document

오류 메시지가 있을 경우, 구글링의 대부분은 아직 페이지가 로딩 완료되지 않았기 때문에, 해당 엘리먼트에 접근할 수 없는 경우로, 대개  sleep()을 넣는 것으로 대처법을 소개하고 있다.

필자의 경우는 위와 같은 상황은 아닙니다.

 

첫 페이지 URL에서  href를 찾고,       ------------------ (1)

for문으로

      각 href로 이동하여,

      그 href에 존재하는 자식 레벨의 href를 찾는다.

 

근데, for 이 한 번 돌고, 2번째 돌때,   (1)에 의해 있던  리스트의 2번째 요소를 접근하지 못하고,

"stale element reference element is not attached to the page document"의 메시지를 출력한다.

 

해결책은 다시 해당 '탭' 즉  해당 리스트를 뽑았던 '탭'으로 되돌아가야 한다. 

driver.SwitchTo().Window(parentWindow);.

 

따라서,  각 element에 접근할 때 이미 추출해 놓았다 하더라도,  그 추출했던 '탭' 소스로 가야 한다는 것입니다.

 

728x90
반응형
728x90
반응형

웹 이벤트를 자동(batch)수행하기 위해 Selenium기반으로 C#으로 접근해 보았습니다.

 

기능하고자 한 것은

   1. 신문사의 특정 기사에 접근

   2. Tag를 찾아내서  그 하이퍼링크된 주소를  클릭

   3. 새창으로 열린 창으로 접근

   4. 특정 iframe을 찾기 및 iframe 선택

   5. Javascript 구문을 수행하기

   6. PageSource에 접근하여 내용 수정

   7. 페이지 코드를 파일로 저장

 

 

728x90

 

 

ChromdeDriver를 생성하여 그 인터페이스(Interface)를 사용합니다.

IWebDriver driver = new ChromeDriver(options)

       

 

크롬 웹브라우저를 열 URL을 지정합니다. 반환값은 처리한 URL입니다. 즉, 그대로 출력합니다.

 string strResult = driver.Url = "https://www.etnews.com/20230331000229";   // implicitly  wait until the load is complete.
 Console.WriteLine(strResult);

 

 

제대로 URL이 열렸는지는 Title 값을 활용하여 Heuristic하게 프로그래밍 했습니다.

 if (driver.Title.IndexOf("missing.html") == -1)

 

 

특정 태그('a')를 찾아 그 이름이 "Englisth"일 경우,  그 하이퍼링크 URL을 호출(click)합니다. 

IList<IWebElement> links = driver.FindElements(By.TagName("a"));
//Console.WriteLine(links[0].Text);
//links.First(element => element.Text == "English").Click();
foreach (var link in links)
{
    Console.WriteLine(link.Text);
    if (link.Text == "English")
    {
        Console.WriteLine(link.GetAttribute("href"));
        link.Click();
        break;
    }
}

 

 

'새창'으로 열렸기 때문에,  제어권을 '새창'으로 옮깁니다.(SwitchTo)

string originWindow = driver.CurrentWindowHandle;
Console.WriteLine(originWindow);
foreach (string window in driver.WindowHandles)
{
    //새창을 찾는다.
    if (originWindow != window)
    {
        Console.WriteLine(window);
        driver.SwitchTo().Window(window);
        break;
    }
}

 

 

특정 iFrame 요소를 찾습니다.

List<IWebElement> frames = new List<IWebElement>(driver.FindElements(By.TagName("iframe")));
Console.WriteLine("Number of Frames: " + frames.Count);
var bFoundResultPage = 0;
for (int i = 0; i < frames.Count; i++)
{
    Console.WriteLine("frame[" + i + "]: " + frames[i].GetAttribute("id").ToString());
    if (frames[i].GetAttribute("id").ToString() == "CSLiResulPage")
    {
        bFoundResultPage = 1;
    }
}

 

특정 iFrame을 사용합니다.

driver.SwitchTo().Frame("CSLiResultPage");

 

JavaScript를 수행하여, 속성을 바꾸어 봅니다.

IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
//js.ExecuteScript("window.open()");
js.ExecuteScript("document.getElementsByTagName(\"html\")[0].setAttribute(\"lang\",\"en\") ");

 

웹페이지소스코드의 내용을 수정해 봅니다.

string aaa = driver.PageSource.ToString();
string bbb = aaa.Replace("https://trans.etnews.com", "http://klaud.between.io");
//Console.WriteLine(bbb);

 

 

 

 

 

전체 소스코드는 아래와 같습니다.

( 메모리 최적화 delete ,   sleep 대신에 await 등 처리 대기 등은  더 최적화 되어야 합니다.^^)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium;

namespace WebCrawler
{
    static class Program
    {
        static void Main(string[] args)
        {
            // ChomeDriver 인스턴스 생성                        
            ChromeOptions options = new ChromeOptions();
            options.AddArguments("--test-type");
            options.AddArguments("--ignore-certificate-errors");
                                    
            using ( IWebDriver driver = new ChromeDriver(options) )
            {
                // URL로 접속 
                string strResult = driver.Url = "https://www.etnews.com/20230331000229";   // implicitly  wait until the load is complete.
                Console.WriteLine(strResult);

                if (driver.Title.IndexOf("missing.html") == -1)
                {

                    // 대기 설정. (find로 객체를 찾을 때까지 검색이 되지 않으면 대기하는 시간 초단위)
                    driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(2);

                    Thread.Sleep(1000);

                    IList<IWebElement> links = driver.FindElements(By.TagName("a"));
                    foreach (var link in links)
                    {
                        Console.WriteLine(link.Text);
                        if (link.Text == "English")
                        {
                            Console.WriteLine(link.GetAttribute("href"));
                            link.Click();
                            break;
                        }
                    }


                    // 5초 기다린다.
                    Thread.Sleep(5000);

                    // 기존창 대신에 새창에서 열린다.
                    string originWindow = driver.CurrentWindowHandle;
                    Console.WriteLine(originWindow);
                    foreach (string window in driver.WindowHandles)
                    {
                        //새창을 찾는다.
                        if (originWindow != window)
                        {
                            Console.WriteLine(window);
                            driver.SwitchTo().Window(window);
                            break;
                        }
                    }

                    // iFrame 찾기
                    List<IWebElement> frames = new List<IWebElement>(driver.FindElements(By.TagName("iframe")));
                    Console.WriteLine("Number of Frames: " + frames.Count);
                    var bFoundResultPage = 0;
                    for (int i = 0; i < frames.Count; i++)
                    {
                        Console.WriteLine("frame[" + i + "]: " + frames[i].GetAttribute("id").ToString());
                        if (frames[i].GetAttribute("id").ToString() == "CSLiResulPage")
                        {
                            bFoundResultPage = 1;
                        }
                    }

                    if (bFoundResultPage == 1)
                    {
                        driver.SwitchTo().Frame("CSLiResultPage");
                        
                        IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
                        js.ExecuteScript("document.getElementsByTagName(\"html\")[0].setAttribute(\"lang\",\"en\") ");


                        string aaa = driver.PageSource.ToString();
                        string bbb = aaa.Replace("https://trans.etnews.com", "http://klaud.between.io");
                        //Console.WriteLine(bbb);


                        File.WriteAllText("C:\\UsersDownloads\\PageSource.html", bbb);
                        //File.WriteAllText("C:\\UsersDownloads\\PageSource.html", driver.PageSource);

                        // 5초 기다린다.
                        Thread.Sleep(1000);
                    }                    
                }
                driver.Quit();
            }
           
            // 아무 키나 누르면 종료
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }

    }
}
728x90
반응형

+ Recent posts