Crawling 정리

robots.txt

크롤링 가능 범위를 작성한 파일이다. 현재 블로그의 url 주소는 https://denev6.tistory.com/이고 https://denev6.tistory.com/robots.txt에 해당 내용이 정리되어 있다.

User-agent: *
Disallow: /owner
Disallow: /manage
Disallow: /admin
Disallow: /oldadmin
Disallow: /search
Disallow: /m/search
Disallow: /m/admin
Disallow: /like
Allow: /

...

User-agent: *는 모든 유저를 뜻하고, Disallow에 제시된 URL을 제외하고 모든 범위를 허용(Allow)하겠다는 의미이다. 


Requests

import requests

URL = "https://denev6.tistory.com/"
headers = {"User-Agent": "..."}
request = requests.get(URL, headers=headers)

if request.status_code == 200:
    # 200: OK
    ...

get을 활용해 URL의 페이지를 가져온다. statue_codeHTTP 상태 코드를 뜻한다. 대표적으로 200은 OK를 뜻하고, 404는 Not Found를 뜻한다. headers에 들어가는 정보는 접근하는 웹페이지에 (크롤링 봇이 아닌) 유저가 접근하는 것처럼 속이기 위해 사용된다. WhatIsMyBrowser에서 자신의 유저 정보를 확인할 수 있다. 

requests.get() 결과: 

<!doctype html>
<html lang="ko">
<head>
	<link rel="stylesheet" type="text/css"
		href="https://t1.daumcdn.net/tistory_admin/lib/lightbox/css/lightbox.min.css" />
	<link rel="stylesheet" type="text/css"
		href="https://t1.daumcdn.net/tistory_admin/assets/blog/tistory-c4444585f105cc25ea3d29e722d9f859072e4864/blogs/style/content/font.css?_version_=tistory-c4444585f105cc25ea3d29e722d9f859072e4864" />
	<link rel="stylesheet" type="text/css"
		href="https://t1.daumcdn.net/tistory_admin/assets/blog/tistory-c4444585f105cc25ea3d29e722d9f859072e4864/blogs/style/content/content.css?_version_=tistory-c4444585f105cc25ea3d29e722d9f859072e4864" />

	(생략)

	<div class="layer_tooltip">
		<div class="inner_layer_tooltip">
			<p class="desc_g"></p>
		</div>
	</div>
	<div id="tistoryEtcLayer" class="layer_post"></div>
	<div id="tistorySnsLayer" class="layer_post"></div>
</body>
</html>

BS4

bs4는 HTML 코드를 쉽게 다룰 수 있는 파이썬 라이브러리이다. 위처럼 requests로 HTML 코드 전체를 가져오고, BS로 필요한 정보를 수집한다. 

import requests
from bs4 import BeautifulSoup

URL = "https://denev6.tistory.com/"
request = requests.get(URL)
soup = BeautifulSoup(request.text, "lxml")
# soup = BeautifulSoup(request.text, "html.parser")

html.parser는 별도의 설치가 필요 없지만, lxml을 사용하기 위해서는 lxml을 설치해야 한다. 일반적으로 lxml의 속도가 더 빠르다. 

soup.find("tag", attrs={"class": "user-uploads"})
soup.find("tag", text="some txt here")
soup.find_all("tag", attrs={"class": "account-profile"})
soup.select_one(
    "#content > div.spot.section_keyword > div.home_section.active"
)

BS로 필요한 정보를 가져오는 방법은 다양하다. 위 예시에서 tag로 표시된 부분은 a, img와 같은 HTML 태그가 들어가는 부분이다. 


Selenium

selenium은 동적인 크롤링을 수행할 때 사용할 수 있다. 구글 이미지나 유튜브 페이지를 살펴보면 처음부터 모든 정보를 보여주는 것이 아니라 스크롤이나 버튼 클릭과 같은 액션을 통해 데이터를 추가로 가져온다. 따라서, selenium을 이용해 특정 동작을 수행해 데이터를 모두 생성한 상태에서 크롤링을 수행한다. 

from selenium import webdriver

URL = "https://denev6.tistory.com/"
driver_path = "chromedriver.exe"
browser = webdriver.Chrome(driver_path)
browser.get(URL)
# browser.maximize_window()

 selenium은 브라우저를 파이썬 코드로 제어하기 때문에 별도의 driver를 설치해야 한다. 위 예시는 Chrome driver이며, 현재 사용중인 크롬 브라우저 버전에 맞는 드라이버를 다운로드하여 사용해야 한다.

browser.find_element_by_xpath("//*[@id='recommendationList']/ul/li[1]")
browser.find_element_by_link_text("search")
browser.find_element_by_id("id").clear()
browser.find_element_by_class_name("class")
browser.find_element_by_css_selector(".profile > div > a")

xpath, id, class 등 다양한 방법으로 요소를 특정할 수 있으며, css_selector는 CSS에서 요소를 특정하는 방식과 같다. 

browser.find_element_by_id("id").clear()
browser.find_element_by_id("id").send_keys("naver_id")
browser.find_element_by_class_name("link_login").click()
browser.close()  # 현재 탭만 종료
browser.quit()  # 전체 브라우저 종료

그 외 다양한 동작을 수행할 수 있다.

import time

previous_height = 0
PAUSE = 2

while True:
    browser.execute_script("window.scrollTo(0, document.body.scrollHeight)")

    time.sleep(PAUSE)

    current_height = browser.execute_script("return document.body.scrollHeight")
    if current_height == previous_height:
        break

    previous_height = current_height

위에서 말했던 스크롤을 통해 정보를 불러오는 과정을 나타낸 코드이다. execute_script를 활용해 JavaScript 코드를 실행할 수 있기 때문에, scrollTo로 화면을 이동한다.