링크에 있는 것을 한꺼번에 다운 받기

2018. 3. 14. 03:19Python-이론/python

링크에 연관되어 있는 모든 파일 다운받아오기



링크와 관련된 모든 파일들을 다운받아 오는 코드를 사용해보겠다. 하지만 이전에 상대주소를 절대주소로 바꾸는 것 부터 해보자!!



from urllib.parse import *

base = "http://example.com/"

print(urljoin(base,'./hoony'))
print(urljoin(base,'./a/b.png'))
print(urljoin(base,"http://example2.com"))
print(urljoin(base,"//example3.com"))




urllib모듈을 사용하여 urljoin 함수를 사용해 상대주소를 절대주소로 바꿀 수 있다. 왼쪽에는 기존의 주소가 들어가고 오른쪽 파라미터에는 상대주소가 들어가면 절대주소로 바꾸어 준다. 하지만 오른쪽 파라미터에 절대주소가 들어간다면 오른쪽 파라미터가 그대로 반환된다. 이제 지금까지 공부한 것을 바탕으로 어떠한 링크에 관련된 모든 파일을 다운받아보자.



한 웹사이트와 관련된 모든 파일을 받기 위해서는 재귀적으로 문제를 해결할 필요가 있다. 첫 html에서 다른 html로 옮겨 가는 a태그의 href 속성의 주소가 있을 것이고 그 주소를 타고 들어가면 또 다른 주소가 있을 것이다. 한번 방문한 주소에서 모든 것을 다운 받은 후 다신 접근 못하게 막게 코드를 짜야한다. urllib은 url을 통한 파일 다운로드 BeautifulSoap는 html코드 분석 등에 이용됨을 유의하면서 코드를 보자



from bs4 import BeautifulSoup
from urllib.request import *
from urllib.parse import *
from os import makedirs
import os.path, time, re

processed_file = {
}

def enum_links(html, base):
    soup = BeautifulSoup(html, 'html.parser')
    links = soup.select("link[rel='stylesheet']") #css파일을 다운받기 위한 링크 찾기
    links += soup.select('a[href]') #a 태그 중 href있는 것만 찾기
    results = []
    for a in links:
        href = a.attrs['href'] #href주소 값만 뽑아내기
        url = urljoin(base,href) #href를 통한 절대 주소 만들기
        results.append(url) #결과에 찾은 url 붙여주기
    return results

def download_file(url):
    o = urlparse(url) #url로 파싱해주기
    savepath = './allDownloadResult/'+o.netloc+o.path #저장될 위치를 결정 netloc는 www.naver.com 같은 주소 path는 쿼리를 제외한 뒷주소이다.
    if re.search(r"/$",savepath): #폴더라면 index.html  /$이런식으로 끝나면 index.html로 이름 짓는다.
        savepath+= "index.html" 
    savedir = os.path.dirname(savepath) #이 파일이 저장된 폴더의 위치를 반환
    print("savedir:",savedir)
    if os.path.exists(savepath): return savepath #이미 파일이 있다면 
    if not os.path.exists(savedir): #폴더가 없다면 
        makedirs(savedir) #폴더 만듬
    try:
        print("download=",url)
        urlretrieve(url, savepath) #url파일 다운로드
        time.sleep(1)
        return savepath
    except:
        print("다운 실패",url)
        return None

def analyze_html(url, root_url):
    savepath = download_file(url) #첫 url다운로드
    if savepath is None: return
    if savepath is processed_file: return #이미 한번 방문했으면 넘어감
    processed_file[savepath] = True #방문 체크
    print("analyze_html=",url)
    html = open(savepath,"r",encoding="utf-8").read()#url의 html파씽
    links = enum_links(html, url) #a태그의 href속성 값 + css파일 url 가져오기

    for link_url in links:
        if link_url.find(root_url) !=0 :
            if not re.search(r".css$",link_url):continue
        if re.search(r".(html|htm)$",link_url): #html파일을 찾았으면 
                analyze_html(link_url, root_url) #새로 얻어낸 html 파일을 분석 재귀사용
                continue
        download_file(link_url) #css파일 다운

if __name__ == "__main__":
    url = "https://www.naver.com/"
    analyze_html(url,url)


생성된 파일들
,br>

사실 처음에는 많이 어려웠지만 계속 보고 찾아보니 그렇게 많이 어렵지는 않았다. 하지만 생각해주어야 할 것이 재귀를 통해서 한번 다운 받은 파일은 다신 안다운 받게 해주기 위해 전역 변수 쓸것 href와 css url만 끌고 올 것 을 잘 생각 해주면서 사용하면 될 것같다. 네이버는 파일이 많아서 그런지 오류가 뜨더라 다른 사이트는 괜찮았다.