2019년 8월 11일 일요일

web page 크롤링(crawling) , 스크레이핑(scraping)시 python으로 다음 페이지 주소 접속하는 방법 / urlparse / urljoin / urllib.parse


설명이 일단 복잡합니다.
앞에서 crawling시 form에 대한 처리를 할때 처리에 관한 가장 기본적인 설명은 아래에 있습니다.
https://swlock.blogspot.com/2019/07/web-page-crawling-scraping-form-postget.html

form을 사용하면 action 항목이 있다고 했습니다.
action : 폼을 전송할 서버 쪽 스크립트 파일을 지정합니다.
즉, form에 전송할 다음 페이지 정보가 저장되어 있습니다. 앞선 예제에서 <form id="sform" name="sform" action="https://search.naver.com/search.naver" method="get"> https로 시작하는 전체 url 정보가 들어있다면 따로 추가 작업이 필요없지만, 일반적으로는 상대 주소를 포함한 page정보가 있습니다.

이것은 form의 action만이 아니라 A tag 및 모든 주소가 있는곳에서 동일하게 일어납니다.
아래는 daum기사 중 html 소스 한 곳입니다.

daum web page의 한 곳
<div id="kakaoGnb" role="navigation">
    <div class="inner_gnb">
        <h2 class="screen_out">뉴스 메인메뉴</h2>
        <ul class="gnb_comm #GNB#default">
            <li class="on"><a href="/" class="link_gnb link_gnb1 #media_home"><span class="screen_out">선택됨</span><span class="ir_wa"></span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/society/" class="link_gnb link_gnb2 #media_society"><span class="ir_wa">사회</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/politics/" class="link_gnb link_gnb3 #media_politics"><span class="ir_wa">정치</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/economic/" class="link_gnb link_gnb4 #media_economic"><span class="ir_wa">경제</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/foreign/" class="link_gnb link_gnb5 #media_foreign"><span class="ir_wa">국제</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/culture/" class="link_gnb link_gnb6 #media_culture"><span class="ir_wa">문화</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/digital/" class="link_gnb link_gnb7 #media_digital"><span class="ir_wa">IT</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/ranking/popular/" class="link_gnb link_gnb8 #media_ranking"><span class="ir_wa">랭킹</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/series/" class="link_gnb link_gnb9 #media_series"><span class="ir_wa">연재</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/photo/" class="link_gnb link_gnb10 #media_photo"><span class="ir_wa">포토</span><span class="bar_gnb"><span class="inner_bar"></span></span></a></li>
            <li><a href="/tv/" class="link_gnb link_gnb11 #media_tv"><span class="ir_wa">TV</span><span class="bar_gnb"><span class="inner_bar"></span></span><em class="ico_news ico_live">LIVE</em></a></li> 

a href 주소에 "/society/" 링크가 있습니다.
web crawling 을 하려면 한 페이지만 읽는것이 아니라 html 코드나 form코드에서 다음 주소를 찾아서 추가로 진행해야하는것이 필 수 입니다.
그러면 저 상대 주소는 내가 접속한 page+상대 주소 입니다.

구현 이론

즉, http://www.daum.net/ 으로 접속했다고 했고, 만약 거기 html응답을 분석했는데 link의 상대 주소가 위와 같이 나왔다고 한다면, http://www.daum.net/society/ 이런식으로 합쳐서 보내면 됩니다만, 실제 구현은 그렇게 단순 하지 않습니다.

우리가 접속하는 http://www.daum.net/ 접속은 실제 webpage 의 '/'를 의미 하지 않을 수 있습니다. 이것은 무슨 말이냐면 저 주소를 접속했지만 실제는 내부적으로  http://www.daum.net/abc/index.html 같은 위치의 html을 우리에게 넘겨 줄 가능성이 있다는 뜻입니다. 그래서 다음 주소는 http://www.daum.net/abc/society/ 이런 형태가 되어야 할 수도 있다는 의미입니다.(https://docs.python.org/ site의 경우)

또 다른 문제점은  http://www.daum.net/abc/index.html 이런 주소를 넘겨줬을때 html코드가 ../society/ 이런 형태가 될 수도 있다는 사실입니다. 그러면 두개 주소를 합쳐서 http://www.daum.net/abc/../society/ 이런 주소가 되며 http://www.daum.net/society/ 이런식으로 다음 접속 경로를 설정해야 할 수도 있습니다. 결론적으로 우리가 지금 접속한 web page의 정확한 경로를 알아야 하고 또한 다음 page link를 정확히 추출해서 다음 page를 생성 해내야합니다. 이때 ".."와 같은 상대 경로 url path를 절대 경로로 만들어 줘야 합니다. (urljoin 사용)

서론이 길었습니다. 위 내용을 python을 이용해 구현해 보았습니다.

Python3 예제
import requests
URL = "https://docs.python.org/"
res = requests.get(URL)
print("requested url:",res.url) # 접속한 url 정보

from bs4 import BeautifulSoup
bsObj = BeautifulSoup(res.text, "html.parser")

# 첫번째 a 태그 뽑아오기
first_a = bsObj.find("a")
print(first_a)

# 글자만 뽑아오기
print(first_a.text)
print("href",first_a.get("href"))

# 이 주소로 접속 하면 안됨
print(URL+first_a.get("href"))

# urljoin 사용해야함
from urllib.parse import urljoin
have_to_get_url = urljoin(res.url, first_a.get("href"))
print(have_to_get_url)

"""
requested url: https://docs.python.org/3/
<a accesskey="I" href="genindex.html" title="General Index">index</a>
index
href genindex.html
https://docs.python.org/genindex.html
https://docs.python.org/3/genindex.html
"""

모듈 설치 하기

pip install BeautifulSoup4
pip install requests

소스 설명


위 예제의 경우 https://docs.python.org/ 주소로 접속했는데 실제 접속하고 나니 https://docs.python.org/3/ 이런 주소로 접속했다고 나오게 되고 이때 A tag 주소를 잘못 사용하면 어뚱한곳으로 접속하게 됩니다.
urljoin을 이용하여 https://docs.python.org/3/genindex.html 과 같은 주소를 접속하는 예제 입니다.



댓글 없음:

댓글 쓰기