개발/C#

# Selenium (웹 테스팅 프레임워크 / Crawling)

노마드 2021. 1. 29. 07:35

# Chrome 버전과 같은 Driver를 사용하지 않으면 Selenium을 사용할 수 없기 때문에

먼저 버전을 확인하고 버전에 맞는 Driver를 다운 받는 것이 좋다.

혹 버전과 Driver가 일치할 수도 있기 때문에 일단 실행해보고, Driver 버전 오류 발생시

드라이버를 다운 받아도 된다

 

 

# Chrome 버전과 같은 버전의 Driver를 실행파일이 있는 경로에 위치시켜야한다.

그게 아닐 경우에는 실행 파일이 있는 경로를 지정하여 드라이버 객체를 생성한다.

 

//IWebDriver driver = new ChromeDriver(@"C:\Users\k\Downloads\chromedriver_win32");

 


 

# Chrome 버전 확인

 

 


 

# Chrome 버전에 맞는 Driver 다운로드

 

https://chromedriver.chromium.org/downloads

 

 


 

# Nuget 패키지 설치

 

Selenium.WebDriver 하나만 설치하면 된다.  

 


 

# 사용 예 - 네이버 크롤러 만들기

 

 

 

 

 


 

# 소스 코드

 

using OpenQA.Selenium;

using OpenQA.Selenium.Chrome;

using System;

using System.Diagnostics;

using System.Windows.Forms;

namespace WindowsFormsApp1

{

  public partial class Form1 : Form

  {

    string result1,result2,result3,result4,result5,result6,result7,result8;

    public Form1()

    {

      InitializeComponent();

    }

    private void Search_btn_Click(object sender, EventArgs e)

    {

      ChromeDriverService service = ChromeDriverService.CreateDefaultService();

      service.HideCommandPromptWindow = true;

      IWebDriver driver = new ChromeDriver(service);

      driver.Url = "https://www.naver.com";

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

      driver.FindElement(By.Name("query")).SendKeys(textBox1.Text);

      driver.FindElement(By.Id("search_btn")).Click();

      listBox1.Items.Clear();

      listBox2.Items.Clear();

      try

      {

        listBox1.Items.Add(driver.FindElement(By.XPath("//*[@id=\"sp_blog_1\"]/dl/dt/a")).Text);

        result1 = driver.FindElement(By.XPath("//*[@id=\"sp_blog_1\"]/dl/dd[3]/span/a[2]")).Text;

        listBox1.Items.Add(driver.FindElement(By.XPath("//*[@id=\"sp_blog_2\"]/dl/dt/a")).Text);

        result2 = driver.FindElement(By.XPath("//*[@id=\"sp_blog_2\"]/dl/dd[3]/span/a[2]")).Text;

        listBox1.Items.Add(driver.FindElement(By.XPath("//*[@id=\"sp_blog_3\"]/dl/dt/a")).Text);

        result3 = driver.FindElement(By.XPath("//*[@id=\"sp_blog_3\"]/dl/dd[3]/span/a[2]")).Text;

        listBox1.Items.Add(driver.FindElement(By.XPath("//*[@id=\"sp_blog_4\"]/dl/dt/a")).Text);

        result4 = driver.FindElement(By.XPath("//*[@id=\"sp_blog_4\"]/dl/dd[3]/span/a[2]")).Text;

      }

      catch { listBox1.Items.Add("블로그가 없습니다."); }

      try

      {

        listBox2.Items.Add(driver.FindElement(By.XPath("//*[@id=\"videoItem0\"]/dl/dt/a")).Text);

        result5 = driver.FindElement(By.XPath("//*[@id=\"videoItem0\"]/dl/dt/a")).GetAttribute("href");

        listBox2.Items.Add(driver.FindElement(By.XPath("//*[@id=\"videoItem1\"]/dl/dt/a")).Text);

        result6 = driver.FindElement(By.XPath("//*[@id=\"videoItem1\"]/dl/dt/a")).GetAttribute("href");

        listBox2.Items.Add(driver.FindElement(By.XPath("//*[@id=\"videoItem2\"]/dl/dt/a")).Text);

        result7 = driver.FindElement(By.XPath("//*[@id=\"videoItem2\"]/dl/dt/a")).GetAttribute("href");

        listBox2.Items.Add(driver.FindElement(By.XPath("//*[@id=\"videoItem3\"]/dl/dt/a")).Text);

        result8 = driver.FindElement(By.XPath("//*[@id=\"videoItem3\"]/dl/dt/a")).GetAttribute("href");

      }

      catch { listBox2.Items.Add("동영상이 없습니다."); }

      if (driver.Manage().Window == null) driver.Close();        // 이렇게 하면 창은 남기고 드라이버만 닫을 수 있다.

    }

    private void SearchResult_btn_Click(object sender, EventArgs e)

    {

      ChromeDriverService service = ChromeDriverService.CreateDefaultService();

      service.HideCommandPromptWindow = true;

      IWebDriver driver = new ChromeDriver(service);

      if (listBox1.SelectedItem != null && listBox2.SelectedItem == null)

      {

        if (listBox1.SelectedIndex.Equals(0)) driver.Url = "http://" + result1;

        else if (listBox1.SelectedIndex.Equals(1)) driver.Url = "http://" + result2;

        else if (listBox1.SelectedIndex.Equals(2)) driver.Url = "http://" + result3;

        else if (listBox1.SelectedIndex.Equals(3)) driver.Url = "http://" + result4;

      }

      else if (listBox2.SelectedItem != null && listBox1.SelectedItem == null)

      {

        if (listBox2.SelectedIndex.Equals(0)) driver.Url = result5;

        else if (listBox2.SelectedIndex.Equals(1)) driver.Url = result6;

        else if (listBox2.SelectedIndex.Equals(2)) driver.Url = result7;

        else if (listBox2.SelectedIndex.Equals(3)) driver.Url = result8;

      }

      if(driver.Manage().Window == null) driver.Close();        // 이렇게 하면 창은 남기고 드라이버만 닫을 수 있다.

    }

    private void BlackGroundSearch_btn_Click(object sender, EventArgs e)

    {

      ChromeDriverService service = ChromeDriverService.CreateDefaultService();

      service.HideCommandPromptWindow = true;

      ChromeOptions options = new ChromeOptions();

      options.AddArguments("headless");

      IWebDriver driver = new ChromeDriver(service,options);

      driver.Url = "https://www.naver.com";

      driver.FindElement(By.Name("query")).SendKeys(textBox1.Text);

      driver.FindElement(By.Id("search_btn")).Click();

      listBox1.Items.Clear();

      listBox2.Items.Clear();

      try

      {

        listBox1.Items.Add(driver.FindElement(By.XPath("//*[@id=\"sp_blog_1\"]/dl/dt/a")).Text);

        result1 = driver.FindElement(By.XPath("//*[@id=\"sp_blog_1\"]/dl/dd[3]/span/a[2]")).Text;

        listBox1.Items.Add(driver.FindElement(By.XPath("//*[@id=\"sp_blog_2\"]/dl/dt/a")).Text);

        result2 = driver.FindElement(By.XPath("//*[@id=\"sp_blog_2\"]/dl/dd[3]/span/a[2]")).Text;

        listBox1.Items.Add(driver.FindElement(By.XPath("//*[@id=\"sp_blog_3\"]/dl/dt/a")).Text);

        result3 = driver.FindElement(By.XPath("//*[@id=\"sp_blog_3\"]/dl/dd[3]/span/a[2]")).Text;

        listBox1.Items.Add(driver.FindElement(By.XPath("//*[@id=\"sp_blog_4\"]/dl/dt/a")).Text);

        result4 = driver.FindElement(By.XPath("//*[@id=\"sp_blog_4\"]/dl/dd[3]/span/a[2]")).Text;

      }

      catch { listBox1.Items.Add("블로그가 없습니다."); }

      try

      {

        listBox2.Items.Add(driver.FindElement(By.XPath("//*[@id=\"videoItem0\"]/dl/dt/a")).Text);

        result5 = driver.FindElement(By.XPath("//*[@id=\"videoItem0\"]/dl/dt/a")).GetAttribute("href");

        listBox2.Items.Add(driver.FindElement(By.XPath("//*[@id=\"videoItem1\"]/dl/dt/a")).Text);

        result6 = driver.FindElement(By.XPath("//*[@id=\"videoItem1\"]/dl/dt/a")).GetAttribute("href");

        listBox2.Items.Add(driver.FindElement(By.XPath("//*[@id=\"videoItem2\"]/dl/dt/a")).Text);

        result7 = driver.FindElement(By.XPath("//*[@id=\"videoItem2\"]/dl/dt/a")).GetAttribute("href");

        listBox2.Items.Add(driver.FindElement(By.XPath("//*[@id=\"videoItem3\"]/dl/dt/a")).Text);

        result8 = driver.FindElement(By.XPath("//*[@id=\"videoItem3\"]/dl/dt/a")).GetAttribute("href");

      }

      catch { listBox2.Items.Add("동영상이 없습니다."); }

      driver.Close();

    }

    private void WindowClose_btn_Click(object sender, EventArgs e)

    {

      try

      {

        Process[] process = new Process[100];

        process = Process.GetProcessesByName("chrome");

        foreach (Process x in process) x.Kill();

        process = Process.GetProcessesByName("chromedriver");

        foreach (Process x in process) x.Kill();

        process = Process.GetProcessesByName("conhost");

        foreach (Process x in process) x.Kill();

      }

      catch { }

    }

    private void ListBoxReset_btn_Click(object sender, EventArgs e)

    {

      listBox1.SelectedItem = null;

      listBox2.SelectedItem = null;

    }

  }

}


 

# 사용할 요소에 맞는 Tag 찾기


 

태그를 알고 싶은 요소가 있을 경우, 해당 요소에 우클릭 후 검사를 누르면

아래 그림과 같이 그 요소에 맞는 코드를 볼 수 있게 된다.

해당 코드에서 사용할 수 있는 태그가 있는지 찾는다.

 

 

 


 

또는 F12를 눌러 개발자 모드로 들어간 후, Elements 항목을 쭉 마우스로 이동하면서 

내가 원하는 요소의 코드가 나올 때까지 찾는다. 해당 코드에서 사용할 수 있는 태그가 있는지 찾는다.

 

 


 

id나 name 같은 Tag를 사용하기 애매한 경우, XPath를 사용해야한다.

그래서 XPath를 찾는다.

 

 

 

 

 

# Tag 또는 XPath, GetAttribute() 등을 사용해 요소를 특정하여, 요소를 핸들링하기

 


 

 

그래서 내가 원하는 요소에 맞는 코드를 찾았으면, 거기에 내가 쓸 수 있는 태그(Tag)가 어떤게 있는지 살펴본다.

아래에 보면 id , name 등의 태그가 있다. 

 

 

 

FindElement로, 이런 태그들을 이용해서 태그에 매칭되는 요소를 찾는다.

그리고 나서 그 요소에 어떤 텍스트를 입력하거나 (SendKeys),  해당 요소를 클릭한다 (Click() 메서드)

 

 

 

그런데 id와 name 같은 식별 가능한 태그들도 없는 애매한 요소들이 있다. 

이런 요소들은 아래와 같이 XPath라는 임의의 경로값을 이용한다.

 

 

 

그런데 XPath로도 애매한 요소들이 있다.  

아래의 경우 동영상을 재생하기 위해 XPath를 복사해도, 그 XPath를 가지고 동영상을 재생할 수가 없다.

그래서 XPath를 가지고 요소를 찾고 GetAttribute를 이용해 해당 요소의 href에 있는 동영상의 경로를 가져와야만

그 경로를 가지고 동영상을 실행시킬 수가 있게 된다.

 

 

 


 

예를들어 검색툴을 만들때 가장 이상적인 경우는 아래와 같이 FindElements로 하부 태그들을 한번에 가져올 수 있는 상황이다.

태그의 구조를 잘 분석하여, 가급적 XPath를 사용하지 않고, 명확하게 해당 요소를 식별할 수 있는 태그를 찾아서 사용한다.

도저히 그런 태그가 없는 경우에만 XPath를 사용한다.