Python 및 Selenium을 사용한 최신 웹 스크래핑

게시 됨: 2022-03-11

웹 스크래핑은 World Wide Web이 탄생했을 때부터 거의 웹 사이트에서 데이터를 추출하는 데 사용되었습니다. 초기에 스크래핑은 알려진 요소, 태그 및 데이터가 있는 정적 페이지에서 주로 수행되었습니다.

그러나 최근에는 웹 개발의 고급 기술로 인해 작업이 조금 더 어려워졌습니다. 이 기사에서는 새로운 기술 및 기타 요인으로 인해 표준 스크래핑을 방지할 수 있는 경우 데이터를 스크래핑하는 방법을 살펴보겠습니다.

기존 데이터 스크래핑

대부분의 웹사이트는 자동 읽기가 아닌 사람이 읽을 수 있는 페이지를 생성하므로 웹 스크래핑은 주로 웹 페이지의 마크업 데이터(오른쪽 클릭, 소스 보기)를 프로그래밍 방식으로 다이제스트한 다음 해당 데이터에서 프로그램을 허용하는 정적 패턴을 감지하는 것으로 구성되었습니다. 다양한 정보를 "읽고" 파일이나 데이터베이스에 저장합니다.

데이터 스크래핑

보고서 데이터를 찾아야 하는 경우 종종 양식 변수나 매개변수를 URL과 함께 전달하여 데이터에 액세스할 수 있습니다. 예를 들어:

 https://www.myreportdata.com?month=12&year=2004&clientid=24823

Python은 부분적으로 이를 위해 만들어진 다양한 웹 라이브러리로 인해 가장 인기 있는 웹 스크래핑 언어 중 하나가 되었습니다. 인기 있는 라이브러리 중 하나인 Beautiful Soup은 태그(예: 구문 분석 트리)를 검색, 탐색 및 수정할 수 있도록 하여 HTML 및 XML 파일에서 데이터를 가져오도록 설계되었습니다.

브라우저 기반 스크래핑

최근에 나는 꽤 간단해 보이는 스크래핑 프로젝트를 가지고 있었고 그것을 처리하기 위해 전통적인 스크래핑을 사용할 준비가 완전히되었습니다. 하지만 더 깊이 파고들면서 기존의 방법으로는 극복할 수 없는 장애물을 발견했습니다.

세 가지 주요 문제로 인해 표준 스크래핑 방법을 사용할 수 없었습니다.

  1. 자격증. 데이터가 있는 웹 사이트 부분에 액세스하려면 설치해야 하는 인증서가 있었습니다. 초기 페이지에 액세스할 때 내 컴퓨터에 설치된 인증서의 적절한 인증서를 선택하라는 메시지가 표시되고 확인을 클릭합니다.
  2. 아이프레임. 사이트는 iframe을 사용하여 정상적인 스크래핑을 엉망으로 만들었습니다. 예, 모든 iframe URL을 찾은 다음 사이트맵을 구축할 수 있지만 다루기 어려울 수 있습니다.
  3. 자바스크립트. 매개변수(예: 고객 ID, 날짜 범위 등)로 양식을 작성한 후 데이터에 액세스했습니다. 일반적으로 양식을 무시하고 단순히 양식 변수(URL을 통해 또는 숨겨진 양식 변수로)를 결과 페이지에 전달하고 결과를 봅니다. 그러나 이 경우 양식에 JavaScript가 포함되어 있어 정상적인 방식으로 양식 변수에 액세스할 수 없었습니다.

그래서 기존 방식을 버리고 브라우저 기반 스크래핑을 위한 가능한 도구를 살펴보기로 했습니다. 이것은 평소와 다르게 작동합니다. 페이지로 직접 이동하여 구문 분석 트리를 다운로드하고 데이터 요소를 가져오는 대신 "인간처럼 행동"하고 브라우저를 사용하여 필요한 페이지로 이동한 다음 스크랩합니다. 데이터 - 따라서 언급된 장벽을 처리할 필요성을 우회합니다.

셀렌

일반적으로 Selenium은 웹 애플리케이션을 위한 오픈 소스 테스트 프레임워크로 잘 알려져 있습니다. 이를 통해 QA 전문가가 자동화된 테스트를 수행하고, 재생을 실행하고, 원격 제어 기능을 구현할 수 있습니다(로드 테스트 및 여러 브라우저 유형에 대해 많은 브라우저 인스턴스 허용). 제 경우에는 이것이 유용할 것 같았습니다.

웹 스크래핑을 위해 제가 주로 사용하는 언어는 Python입니다. Python에는 일반적으로 필요한 모든 기능을 처리할 수 있는 잘 통합된 라이브러리가 있기 때문입니다. 그리고 확실히 Python용 Selenium 라이브러리가 존재합니다. 이렇게 하면 Chrome, Firefox, IE 등의 "브라우저"를 인스턴스화한 다음 내가 찾고 있는 데이터에 액세스하기 위해 브라우저를 직접 사용하는 척 할 수 있습니다. 그리고 브라우저가 실제로 표시되는 것을 원하지 않으면 "헤드리스" 모드에서 브라우저를 생성하여 어떤 사용자에게도 표시되지 않도록 할 수 있습니다.

프로젝트 설정

실험을 시작하려면 프로젝트를 설정하고 필요한 모든 것을 얻어야 했습니다. 저는 Windows 10 머신을 사용했고 상대적으로 업데이트된 Python 버전(v. 3.7.3)이 있는지 확인했습니다. 빈 Python 스크립트를 만든 다음 라이브러리가 아직 로드되지 않은 경우 PIP(Python용 패키지 설치 프로그램)를 사용하여 필요할 수 있다고 생각되는 라이브러리를 로드했습니다. 다음은 내가 시작한 주요 라이브러리입니다.

  1. 요청(HTTP 요청 작성용)
  2. URLLib3(URL 처리)
  3. Beautiful Soup(셀레늄이 모든 것을 처리할 수 없는 경우)
  4. Selenium(브라우저 기반 탐색용)

또한 스크립트에 일부 호출 매개변수(argparse 라이브러리 사용)를 추가하여 다양한 옵션을 사용하여 명령줄에서 스크립트를 호출하여 다양한 데이터 세트를 가지고 놀 수 있었습니다. 여기에는 고객 ID, ~월/년 및 ~월/년이 포함됩니다.

문제 1 – 인증서

가장 먼저 선택해야 하는 것은 Selenium에 사용할 브라우저를 선택하는 것이었습니다. 저는 일반적으로 Chrome을 사용하고 오픈 소스 Chromium 프로젝트(Edge, Opera 및 Amazon Silk 브라우저에서도 사용됨)를 기반으로 하기 때문에 먼저 Chrome을 사용해 봐야겠다고 생각했습니다.

필요한 라이브러리 구성 요소를 추가한 다음 몇 가지 간단한 명령을 실행하여 스크립트에서 Chrome을 시작할 수 있었습니다.

 # Load selenium components from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait, Select from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException # Establish chrome driver and go to report site URL url = "https://reportdata.mytestsite.com/transactionSearch.jsp" driver = webdriver.Chrome() driver.get(url)

헤드리스 모드에서 브라우저를 실행하지 않았기 때문에 실제로 브라우저가 나타났고 무엇을 하는지 볼 수 있었습니다. 인증서(이전에 설치한)를 선택하라는 메시지가 즉시 표시되었습니다.

가장 먼저 해결해야 할 문제는 인증서였습니다. 웹 사이트에 들어가기 위해 적절한 것을 선택하고 수락하는 방법은 무엇입니까? 스크립트의 첫 번째 테스트에서 다음과 같은 프롬프트를 받았습니다.

데이터 스크래핑

이것은 좋지 않았다. 스크립트를 실행할 때마다 수동으로 확인 버튼을 클릭하고 싶지 않았습니다.

결과적으로 프로그래밍 없이 이에 대한 해결 방법을 찾을 수 있었습니다. Chrome에 시작 시 인증서 이름을 전달할 수 있는 기능이 있기를 희망했지만 해당 기능은 없었습니다. 그러나 Chrome에는 Windows 레지스트리에 특정 항목이 있는 경우 인증서를 자동으로 선택하는 기능이 있습니다. 표시되는 첫 번째 인증서를 선택하도록 설정하거나 더 구체적으로 설정할 수 있습니다. 하나의 인증서만 로드했기 때문에 일반 형식을 사용했습니다.

데이터 스크래핑

따라서 해당 세트를 사용하여 Selenium에게 Chrome을 시작하도록 지시하고 인증서 프롬프트가 표시되면 Chrome은 인증서를 "자동 선택"하고 계속 진행합니다.

문제 2 - Iframe

자, 이제 사이트에 있었고 고객 ID와 보고서 날짜 범위를 입력하라는 양식이 나타났습니다.

데이터 스크래핑

개발자 도구(F12)에서 양식을 검사하여 양식이 iframe 내에 표시된다는 것을 알았습니다. 따라서 양식 작성을 시작하기 전에 양식이 존재하는 적절한 iframe으로 "전환"해야 했습니다. 이를 위해 다음과 같이 Selenium의 전환 기능을 호출했습니다.

 # Switch to iframe where form is frame_ref = driver.find_elements_by_tag_name("iframe")[0] iframe = driver.switch_to.frame(frame_ref)

좋습니다. 이제 올바른 프레임에서 구성 요소를 확인하고 고객 ID 필드를 채우고 날짜 드롭다운을 선택할 수 있었습니다.

 # Find the Customer ID field and populate it element = driver.find_element_by_name("custId") element.send_keys(custId) # send a test id # Find and select the date drop-downs select = Select(driver.find_element_by_name("fromMonth")) select.select_by_visible_text(from_month) select = Select(driver.find_element_by_name("fromYear")) select.select_by_visible_text(from_year) select = Select(driver.find_element_by_name("toMonth")) select.select_by_visible_text(to_month) select = Select(driver.find_element_by_name("toYear")) select.select_by_visible_text(to_year)

문제 3 - 자바스크립트

양식에 남아 있는 유일한 것은 찾기 버튼을 "클릭"하여 검색을 시작하는 것뿐이었습니다. 찾기 버튼이 JavaScript에 의해 제어되는 것처럼 보였고 일반적인 "제출" 유형 버튼이 아니었기 때문에 이것은 약간 까다로웠습니다. 개발자 도구에서 검사한 결과 버튼 이미지를 찾았고 마우스 오른쪽 버튼을 클릭하여 해당 이미지의 XPath를 얻을 수 있었습니다.

데이터 스크래핑

그런 다음 이 정보로 무장하여 페이지에서 요소를 찾아 클릭했습니다.

 # Find the 'Find' button, then click it driver.find_element_by_xpath("/html/body/table/tbody/tr[2]/td[1]/table[3]/tbody/tr[2]/td[2]/input").click()

그리고 짜잔, 양식이 제출되었고 데이터가 나타났습니다! 이제 결과 페이지의 모든 데이터를 스크랩하고 필요에 따라 저장할 수 있습니다. 아니면 내가 할 수 있습니까?

데이터 가져오기

먼저 검색에서 아무것도 찾지 못한 경우를 처리해야 했습니다. 그것은 꽤 간단했습니다. "기록을 찾을 수 없음"과 같은 메시지를 남기지 않고 검색 양식에 표시합니다. 나는 단순히 그 문자열을 검색하고 발견하면 바로 거기에서 멈췄습니다.

그러나 결과가 나온 경우 데이터는 더하기 기호(+)와 함께 div에 표시되어 트랜잭션을 열고 모든 세부 정보를 표시합니다. 열린 거래에는 빼기 기호(-)가 표시되어 클릭하면 div가 닫힙니다. 더하기 기호를 클릭하면 URL을 호출하여 해당 div를 열고 열려 있는 모든 div를 닫습니다.

데이터 스크래핑

따라서 페이지에서 더하기 기호를 찾고 각 기호 옆에 있는 URL을 수집한 다음 각 항목을 반복하여 모든 트랜잭션에 대한 모든 데이터를 가져와야 했습니다.

 # Loop through transactions and count links = driver.find_elements_by_tag_name('a') link_urls = [link.get_attribute('href') for link in links] thisCount = 0 isFirst = 1 for url in link_urls: if (url.find("GetXas.do?processId") >= 0): # URL to link to transactions if isFirst == 1: # already expanded + isFirst = 0 else: driver.get(url) # collapsed +, so expand # Find closest element to URL element with correct class to get tran type tran_type=driver.find_element_by_xpath("//*[contains(@href,'/retail/transaction/results/GetXas.do?processId=-1')]/following::td[@class='txt_75b_lmnw_T1R10B1']").text # Get transaction status status = driver.find_element_by_class_name('txt_70b_lmnw_t1r10b1').text # Add to count if transaction found if (tran_type in ['Move In','Move Out','Switch']) and (status == "Complete"): thisCount += 1

위의 코드에서 내가 검색한 필드는 트랜잭션 유형과 상태였으며 지정된 규칙에 맞는 트랜잭션 수를 결정하기 위해 개수에 추가되었습니다. 그러나 날짜 및 시간, 하위 유형 등과 같은 트랜잭션 세부 정보 내의 다른 필드를 검색할 수 있었습니다.

이 프로젝트의 경우 카운트가 호출 응용 프로그램으로 다시 반환되었습니다. 그러나 그것과 다른 스크랩 데이터는 플랫 파일이나 데이터베이스에도 저장될 수 있습니다.

추가 가능한 장애물 및 솔루션

자신의 브라우저 인스턴스로 최신 웹 사이트를 스크랩하는 동안 수많은 다른 장애물이 나타날 수 있지만 대부분은 해결할 수 있습니다. 다음은 몇 가지입니다.

  • 무언가가 나타나기 전에 찾으려고

    자신을 탐색하는 동안 페이지가 나타날 때까지, 때로는 몇 초 동안 얼마나 자주 기다리고 있습니까? 프로그래밍 방식으로 탐색하는 동안에도 동일한 일이 발생할 수 있습니다. 클래스나 다른 요소를 찾고 있는데 거기에 없습니다!

    운 좋게도 Selenium에는 특정 요소가 표시될 때까지 기다릴 수 있는 기능이 있으며 다음과 같이 요소가 표시되지 않으면 시간 초과될 수 있습니다.

 element = WebDriverWait(driver, 10). until(EC.presence_of_element_located((By.ID, "theFirstLabel")))


  • 보안 문자를 통해 얻기

    일부 사이트에서는 Captcha 또는 이와 유사한 것을 사용하여 원치 않는 로봇(귀하로 간주될 수 있음)을 방지합니다. 이것은 웹 스크래핑에 댐퍼를 설치하고 속도를 늦출 수 있습니다.

간단한 프롬프트(예: "2 + 3이 무엇인가요?")의 경우 일반적으로 쉽게 읽고 파악할 수 있습니다. 그러나 고급 장벽의 경우 이를 해독하는 데 도움이 되는 라이브러리가 있습니다. 몇 가지 예로는 2Captcha, Death by Captcha 및 Bypass Captcha가 있습니다.

  • 웹사이트 구조 변경

    웹사이트는 변경되어야 하며 종종 변경됩니다. 그렇기 때문에 스크래핑 스크립트를 작성할 때 이것을 염두에 두는 것이 가장 좋습니다. 데이터를 찾는 데 사용할 방법과 사용하지 않는 방법에 대해 생각하고 싶을 것입니다. 전체 구를 일치시키려고 하기보다 부분 일치 기술을 고려하십시오. 예를 들어, 웹사이트는 메시지를 "기록을 찾을 수 없음"에서 "기록을 찾을 수 없음"으로 변경할 수 있지만 일치 항목이 "기록 없음"에 있으면 문제가 없습니다. 또한 XPATH, ID, 이름, 링크 텍스트, 태그 또는 클래스 이름 또는 CSS 선택기에서 일치시킬지 여부와 변경 가능성이 가장 적은 항목을 고려하십시오.

요약: Python 및 Selenium

이것은 사용되는 기술과 복잡성에 관계없이 거의 모든 웹 사이트를 스크랩할 수 있음을 보여주는 간단한 시연이었습니다. 기본적으로 사이트를 직접 탐색할 수 있다면 일반적으로 스크랩할 수 있습니다.

이제 주의 사항으로 모든 웹사이트를 스크랩 해야 한다는 의미는 아닙니다. 일부 사이트에는 합법적인 제한이 있으며 특정 사이트를 스크랩하는 것이 합법성을 결정하는 수많은 법원 사건이 있었습니다. 반면에 일부 사이트는 웹 사이트에서 데이터를 검색하도록 환영하고 권장하며 경우에 따라 작업을 더 쉽게 하기 위해 API를 제공합니다.

어느 쪽이든 프로젝트를 시작하기 전에 이용 약관을 확인하는 것이 가장 좋습니다. 그러나 계속 진행하면 작업을 완료할 수 있습니다.

복잡한 웹 스크래핑을 위한 권장 리소스:

  • 고급 Python 웹 스크래핑: 모범 사례 및 해결 방법
  • 확장 가능한 DIY 스크래핑: 대규모로 스크래퍼를 구축하고 실행하는 방법