IT기타

(Selenium 사용) 메인메이지 -> 링크 리스트 -> 상세데이터 수집 (페이징 데이터수집)

emilyyoo 2024. 7. 24. 15:30
728x90

1. 코드 기능 간략 설명

아래 코드는 Selenium을 사용하여

 

특정 웹 페이지에 있는 상세 링크릴 클릭하며 상세 페이지 내에 데이터를 자동으로 수집하는 코드다.

 

페이지네이션을 통해 모든 페이지를 순회하며, 각 페이지에서 원하는 데이터를 추출하고 파일에 저장했다.

 

이와 같은 방법을 사용하면 대량의 데이터를 자동으로 수집할 수 있어 매우 유용하다.

 

특정 신문사에 있는 특정 칼럼만 모아서 한꺼번에 보고 싶어서 만들어 봤다. 

 

 

2. 필요 도구

  • Python
  • Selenium 라이브러리
  • ChromeDriver

 

3. 설치

먼저, Selenium과 ChromeDriver를 설치해야 한다..

pip install selenium

 

ChromeDriver 는 내 블로그 아래 포스트 참고. 

https://betterwe.tistory.com/150

 

4. 코드 설명

4.1. 드라이버 설정 및 실행

먼저 ChromeDriver 경로를 설정하고, Selenium을 사용하여 웹 드라이버를 실행

 

from selenium import webdriver
from seleniuhttp://m.webdriver.chrome.service import Service
from seleniuhttp://m.webdriver.common.by import By
import time

# Chrome 웹 드라이버 경로 설정
driver_path = r'C:\path\to\chromedriver.exe'  # 예: 'C:/path/to/chromedriver.exe'
main_page_url = '링크리스트가 있는 메인 페이지'
base_url = '메인 페이지의 홈주소, 내 경우 신문사 주소였다'

# ChromeService 객체 생성
service = Service(executable_path=driver_path)

# Chrome 웹 드라이버 실행
options = webdriver.ChromeOptions()
options.add_argument('--headless')  # Headless 모드로 실행하여 UI를 표시하지 않음
driver = webdriver.Chrome(service=service, options=options)

 

 

4.2. 페이지에서 링크 추출

메인 페이지에서 모든 링크를 추출

 

def get_links_from_page():
    # 페이지 로딩 대기 (필요에 따라 조정)
    time.sleep(5)
    
    # 메인 페이지에서 모든 링크 가져오기. 여기서 a 태그의 패턴을 파악해야 한다. 특정 클래스이름으로 가져올 수 있는지. 감싸고 있는 div를 찾을 수 있는지 등...

 

    #  나의 경우 a 태그가 내가 찾는 것 외에도 많이 있어서 내가 찾는 a 태그의 링크 패턴을 분석해서 그 링크가 포함된 것들만 가져왔다. 


    links = driver.find_elements(By.CSS_SELECTOR, 'a[href*="공통적으로 들어가는 주소"]')
    
    # 링크 URL 중복 제거
    unique_links = set(link.get_attribute('href').split('?')[0] for link in links if link.get_attribute('href'))
    
    return unique_links

 

 

 

4.3. 링크 페이지에서 내용 추출

각 링크 페이지로 이동하여 <p> 태그의 내용을 추출. 여기서도 자신이 추출하려는 contents의 태그를 파악, 그 클래스의 패턴도 파악하면 좋다. 나의 경우 맨 처음엔 클래스와 태그까지 명확히 명시했지만 동적페이지라서 그런지 잘 찾아지지 않아 무조건 p태그 들만 찾아 그 안에 컨텐츠를 가져왔다. 

 

 

def extract_content(link):
    try:
        driver.get(link)
        time.sleep(5)  # 페이지 로딩 대기 (필요에 따라 조정)
        data_elements = driver.find_elements(By.TAG_NAME, 'p')
        content = ' '.join(element.text for element in data_elements)
        
        if content:
            print(f"Link click: Success, Content extraction: Success")
            print(f"Extracted Content: {content[:200]}...")  # Print first 200 characters for verification
            return content
        else:
            print("Link click: Success, Content extraction: No content found")
            return None
    except Exception as e:
        print(f"Link click: Failed ({str(e)})")
        return None

 

 

4.4. 페이지네이션 처리

여러 페이지에 걸쳐 데이터를 수집하기 위해 페이지네이션을 처리

 

def main():
    driver.get(main_page_url)
    all_links = set()
    page_count = 0  # Page counter

    # Loop through pagination
    while True:
        page_count += 1
        print(f"Crawling page: {page_count}")
        
        # Get links from current page
        links = get_links_from_page()
        all_links.update(links)

        # Try to click the "next" button
        try:
            next_button = driver.find_element(By.CSS_SELECTOR, 'div.next')
            if 'disabled' in next_button.get_attribute('class'):
                break
            next_button.click()
            time.sleep(5)  # 페이지 로딩 대기 (필요에 따라 조정)
        except Exception as e:
            print(f"Pagination failed: {str(e)}")
            break

    print(f"Total pages crawled: {page_count}")
    print(f"Total unique links found: {len(all_links)}")

    with open('output.txt', 'w', encoding='utf-8') as file:
        for link_url in all_links:
            if not link_url.startswith('http'):
                full_link_url = base_url + link_url.lstrip('/')
            else:
                full_link_url = link_url

            print(f'Navigating to: {full_link_url}')
            
            # 구분 표시 추가
            file.write(f'*****================= Navigating to: {full_link_url} *****\n')
            
            content = extract_content(full_link_url)
            if content:
                file.write(content + '\n')

    driver.quit()

if __name__ == "__main__":
    main()

728x90