• 카테고리

    질문 & 답변
  • 세부 분야

    업무 자동화

  • 해결 여부

    미해결

Javascript와 iframe이 포함된 url cawling시 문제점

23.11.22 23:33 작성 조회수 379

0

안녕하세요.

Javascript나 iframe등이 포함된 url을 crawling할때

devTools에서는 분명히 element가 존재하는데

Selenium WebDriver의 page_source에는 추가된 element는 없고

JavaScript와 기타 code만 보이는 문제가 있습니다.

 

Javascript나 iframe등이 실행되고 난 결과의 html,즉 element가 전부 업데이트된 것을 받아 볼수 있는 방법이 없을까요?

sleep,wait등을 충분히 줬는데도 해결이 안되네요.

 

감사합니다. ^^

답변 3

·

답변을 작성해보세요.

0

제가 코드를 실행시켜볼 수 없으니 그냥 코드만 보고 말씀드리자면,

class_name = "rax-view-v2 list--item--26w71PF"

클래스명에 빈칸이 있어서는 안됩니다.

class_name = "rax-view-v2.list--item--26w71PF"

빈칸을 점으로 바꿔주세요. 그리고 이걸 바꿔도

elements=wait.until(EC.presence_of_element_located((By.CLASS_NAME, class_name)))

for element in elements:
    # 작업 수행
    try:
        product_url=element.get_attribute("href");
        print(product_url);
    except Exception:
        pass 

이 부분에서 TypeError: 'WebElement' object is not iterable 에러가 발생할 겁니다.

elements = wait.until(EC.presence_of_element_located((By.CLASS_NAME, class_name)))

이 코드를

elements = wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, class_name)))

이렇게 바꿔야 아래 반복문 사용이 가능합니다. 아니면 반복문을 사용하지 않고

try:
    product_url=elements.get_attribute("href")
    print(product_url)
except Exception:
    pass 

이렇게 하면 한 개만 찾고 한 개만 출력되며 에러가 발생하지 않습니다.

물론 elements=wait.until(EC.presence_of_element_located((By.CLASS_NAME, class_name))) 이 코드 이전에 문제가 발생한다면 그걸 먼저 해결해야겠죠.

김플님, 답변 감사합니다. ^^

지적해 주신대로 아래와 같이 수정하였습니다.

class_name = "rax-view-v2.list--item--26w71PF"
elements=wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, class_name)))

Exception has occurred: TimeoutException

하지만 위와 같이 30초 동안 못찾고 ERROR가 발생합니다.

관련해서 많이 찾아 봤는데 javascript와 iframe등으로 복잡한 구조에서 rendered된 html을 얻으려면 쉽지 않은 과정을 거져야 하는 것 같이 써있는던데요? 어떻게 방법이 없을까요?

쉽지 않습니다. 하지만 포기하지 않고 해결 하고 싶습니다. ^^

벌써 2달째 해매고 있습니다. 도와주세요 ㅠㅠ

0

안녕하세요.
모든 element가 화면에 나타난 다음 page_source를 가져오시면 됩니다.
그리고 코드를 올려주시면 어느 부분이 문제인지 정확하게 짚어드릴 수 있습니다.

김플 안녕하세요. ^^ 미리 감사 드립니다.

전체코드를 보시면 아시겠지만 핵심적인 코드는 밑에 있습니다.

wait = WebDriverWait(driver, 30)
class_name = "rax-view-v2 list--item--26w71PF"
elements=wait.until(EC.presence_of_element_located((By.CLASS_NAME, class_name)))

 

전체 코드는 아래와 같습니다만, taobao에 등록을 하셔야 하는 것이라요. 일단 pw/id제외하고 코드공유하겠습니다.


#("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.106 Safari/537.36")

from webdriver_manager.chrome import ChromeDriverManager 
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.common.exceptions import NoSuchElementException
import time 
from selenium.webdriver.common.keys import Keys

from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.chrome.options import Options

from random import random

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from fake_useragent import UserAgent
from urllib.parse import quote
import time, random


import win32clipboard
from openpyxl import Workbook
import requests
from PIL import Image
import io
from io import BytesIO
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
import re

from requests_html import HTMLSession
import asyncio

def send_to_clipboard(clip_type, data):
    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardData(clip_type, data)
    win32clipboard.CloseClipboard()

options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
user_ag = UserAgent().random
options.add_argument('user-agent=%s'%user_ag)
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
options.add_experimental_option("prefs", {"prfile.managed_default_content_setting.images": 2})
# 비밀번호 저장 대화 상자를 비활성화하는 옵션 설정
prefs = {"credentials_enable_service": False, "profile.password_manager_enabled": False}
options.add_experimental_option("prefs", prefs)
options.add_experimental_option("detach", True)
options.add_argument('--load-extension=c:/source/RobotMon/HackTaobao')
# ChromeDriver 서비스
driver = webdriver.Chrome(options=options)

# 크롤링 방지 설정을 undefined로 변경
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
            Object.defineProperty(navigator, 'webdriver', {
                get: () => undefined
            })
            """
})


wait = WebDriverWait(driver, 30)
#########################################
url = 'https://login.taobao.com/member/login.jhtml'
driver.get(url=url)
driver.maximize_window();

id_input = wait.until(EC.presence_of_element_located((By.ID, "fm-login-id")))
id_input.send_keys('xxxxx')

pw_input = wait.until(EC.presence_of_element_located((By.ID, "fm-login-password")))
pw_input.send_keys('xxxxx')

time.sleep(random.randint(1, 3))
wait.until(EC.presence_of_element_located((By.CLASS_NAME, "fm-button"))).click()

#로그인대기
time.sleep(random.randint(1, 3))


#검색할 영상을 clipbord에 복사한다.
##############################################################333
image_url="https://thumbnail6.coupangcdn.com/thumbnails/remote/230x230ex/image/vendor_inventory/27bb/e09dc0e1e3e611f76774ab21b1eb2746eaf02848cb2153ac3e10d50eb2c2.jpg"
# URL에서 이미지 다운로드
response = requests.get(image_url)
image = Image.open(io.BytesIO(response.content))

# 이미지를 바이트 형식으로 변환
output = BytesIO()
image.convert("RGB").save(output, "BMP")
data = output.getvalue()[14:]
output.close()

# 클립보드에 이미지 복사
send_to_clipboard(win32clipboard.CF_DIB, data)

   
#영상을 검색한다.
#####################################################################################################
url="https://world.taobao.com"

driver.get(url)
time.sleep(3)

inputBox = driver.find_element(By.CLASS_NAME, "rax-textinput")   
# inputBox에 클립보드에 저장한 이미지를 붙여넣는다.
inputBox.send_keys(Keys.CONTROL, 'v')
SearchBtn = driver.find_element(By.CLASS_NAME, "component-preview-button") 
SearchBtn.click();
###################################################################################################


              
class_name = "rax-view-v2 list--item--26w71PF"
elements=wait.until(EC.presence_of_element_located((By.CLASS_NAME, class_name)))

for element in elements:
    # 작업 수행
    try:
        product_url=element.get_attribute("href");
        print(product_url);
    except Exception:
        pass 

 

다양한 방법을 해 봤는데, 내공이 부족한지 아직도 못하고 있네요^^

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2023.11.24

안녕하세요, 인프런 AI 인턴입니다.
만족한 전복님, 질문 주셔서 감사합니다.

JavaScript나 iframe이 포함된 페이지를 Selenium을 통해 크롤링할 때 발생하는 문제에 대해 말씀해 주셨네요. 페이지의 자바스크립트가 작동하여 동적으로 생성되는 요소들은 page_source로 바로 볼 수 없을 때가 많습니다. 여러 가지 방법을 시도해보셨지만 결과가 나오지 않는다면 다음 방법들을 시도해보실 수 있습니다.

  1. 웹드라이버 대기 시간 조정: Selenium의 WebDriverWait을 사용하여 특정 요소가 나타날 때까지 명시적으로 기다리게 할 수 있습니다. 다음은 WebDriverWait을 사용한 예시 코드입니다.
   from selenium import webdriver
   from selenium.webdriver.common.by import By
   from selenium.webdriver.support.ui import WebDriverWait
   from selenium.webdriver.support import expected_conditions as EC
   
   # 웹드라이버 초기화(예: Chrome)
   driver = webdriver.Chrome()

   # 웹 사이트 접속
   driver.get("해당 웹페이지 URL")

   # 요소가 로드될 때까지 대기
   element = WebDriverWait(driver, 10).until(
       EC.presence_of_element_located((By.ID, "해당 요소의 ID"))
   )

   # 이제 element를 사용해 작업을 진행
  1. iframe 내부 요소 처리: iframe 내의 요소에 접근하기 위해서는 먼저 해당 iframe으로 컨텍스트를 전환해야 합니다.
   # iframe 요소를 찾아 전환
   iframe = driver.find_element_by_id('iframe의 id')
   driver.switch_to.frame(iframe)

   # 이제 iframe 내의 요소에 접근 가능
  1. 페이지 소스 대신 요소 직접 추출: 웹 페이지에서 직접 요소의 HTML을 추출해 볼 수 있습니다.
   # 요소를 바로 가져와 HTML을 추출
   html_content = driver.find_element_by_id('해당 요소의 ID').get_attribute('outerHTML')

위 방법들로도 문제가 해결되지 않는다면 추가적인 로그 확인이나 다른 예외 상황을 고려해보아야 할 수 있습니다. 오류 메시지나 로그를 통해 구체적인 문제를 확인해볼 필요가 있습니다.

혹시 더 자세한 도움이 필요하시다면 인프런의 ‘문의하기’를 통해 질문해 보시길 추천드립니다. 강의 내용과 직접적인 관련이 있을 경우, 해당 강의의 ‘수강평 등록’ 혹은 ‘수강평 작성하기’를 통하여 질문이 가능합니다.

크롤링 작업이 원활하게 진행되시길 바라며, 인프런에서 효율적인 웹 크롤링과 웹 페이지 자동화 학습이 되시길 바랍니다.