본문 바로가기
코딩 연습/코딩배우기

이미지 다운로드 관련 requests와 requests-html 비교

by good4me 2022. 1. 11.

goodthings4me.tistory.com


파이썬으로 이미지 다운로드 관련 코딩을 할 때, 동적인 페이지의 문제로 인해 selenium을 많이 사용한다. 그러나 selenium의 단점으로 인해 다른 방법을 찾는 것이 사실인데, 이런 부분을 requests-html로 어느 정도 해결이 되는 것 같아서 다음 이미지 다운로드 방법으로 requests와 requests_html를 비교해본다.

Daum 이미지 다운로드 관련 requests와 requests-html 중 무엇을 사용할 것인가

 

이미지 검색

- 다음에서 이미지만 보여주는 탭에서 최근 화두인 '메타버스' 이미지 검색

 

 

이미지탭 소스코드

- 이미지 링크 주소(URL)가 잘 보인다. requests.get()으로 다운로드 가능할까?

 

 

소스보기 후 검색

- 첫 번째 이미지 소스코드중 https://search4.kakaocdn.net/argon/0x200_85_hr/9H2AVOynrIU 부분을 검색한 결과, 보이긴 하는데, 메모장(아래 이미지)에 옮겨서 보니 html 코드가 아니었다. 상단으로 더 올려 보면 <javascript> 부분이 있음.

소스보기 메모장

 

requests.get() 사용한 경우

import requests
from bs4 import BeautifulSoup

keyword = '메타버스'
url = f'https://search.daum.net/search?w=img&q={keyword}&DA=IIM'

r1 = requests.get(url)
soup = BeautifulSoup(r1.text, 'html.parser')
imgList = soup.find('div', id='imgList')
print(imgList)  
# <div class="cont_img cont_tab" id="imgList"> </div>

img_list = imgList.find_all('div', {'class':'wrap_thumb'})
print(len(img_list))  # 0

- 데이터를 불러오지 못한다.

 

 

requests_html의 HTMLSession() 사용한 경우

from requests_html import HTMLSession

keyword = '메타버스'
url = f'https://search.daum.net/search?w=img&q={keyword}&DA=IIM'

session = HTMLSession()
r = session.get(url)
# r.html.render()
imgList = r.html.find('div#imgList')
print(type(imgList), len(imgList))
# <class 'list'> 1

print(imgList[0])
# <Element 'div' id='imgList' class=('cont_img', 'cont_tab')>

print(imgList[0].html)
# <div id="imgList" class="cont_img cont_tab"> </div>

print(imgList[0].text)  # ''

img_list = r.html.find('div#imgList > div.wrap_thumb > a > img')
print(len(img_list))  # 0

img_list = imgList[0].find('div.wrap_thumb > a > img')
print(len(img_list))  # 0

- imgList[0]과 imgList[0].html은 값을 불러왔으나, imgList[0].text는 데이터가 없다

- 하위 요소(div.wrap_thumb > a > img) 또한 데이터를 불러오지 못한다.

 

아래 코드블럭을 보면, JavaScript 렌더링 기능을 통해 왜 requests_html이 "Full JavaScript support!"이라고 하는지 알 수 있다.

from requests_html import HTMLSession

keyword = '메타버스'
url = f'https://search.daum.net/search?w=img&q={keyword}&DA=IIM'

session = HTMLSession()
r = session.get(url)

r.html.render()
imgList = r.html.find('div#imgList')
print(type(imgList), len(imgList))
# <class 'list'> 1

print(imgList[0])
# <Element 'div' id='imgList' class=('cont_img', 'cont_tab') style='width: 1129px;'>

print(imgList[0].html)
'''
<Element 'div' id='imgList' class=('cont_img', 'cont_tab') style='width: 1129px;'>     
<div id="imgList" class="cont_img cont_tab" style="width: 1129px;"> <div class="wrap_thumb" style="width:296px;height:168px;display:block">
<a href="?w=img&amp;DA=IIM&amp;q=%EB%A9%94%ED%83%80%EB%B2%84%EC%8A%A4&amp;docid=33UvSdma4tW5r0wcpg" class="link_thumb">
<img src="https://search4.kakaocdn.net/argon/0x200_85_hr/9H2AVOynrIU" data-src="https://search4.kakaocdn.net/argon/0x200_85_hr/9H2AVOynrIU" class="thumb_img" alt="&#xBA54;&#xD0C0;&#xBC84;&#xC2A4; Metaverse" style="width:299px;height:168px;margin-left:-1px" data-size="296x168" onerror="SF.errorImage(this)"/>
</a>
<div class="info_img">
<a href="javascript:;" class="link_info" title="&#xBA54;&#xD0C0;&#xBC84;&#xC2A4; Metaverse">
<strong class="tit_img"><b>메타버스</b> Metaverse</strong> ....

'''

print(imgList[0].text)
'''
메타버스 Metaverse 블로그
원본
메타버스 관련주 블로그
원본
'Z세대 흐름' 메타버스 읽는 사람들..미래 지향 전망서 인기 2021.10.26       
원본
메타버스 블로그
원본 ....

'''

img_list = r.html.find('div#imgList > div.wrap_thumb > a > img')
print(len(img_list))  # 80

img_list = imgList[0].find('div.wrap_thumb > a > img')
print(len(img_list))  # 80

for img in img_list:
    img_src = img.attrs['src']
    alt = img.attrs['alt']
    print(img_src, alt)
    '''
    https://search4.kakaocdn.net/argon/0x200_85_hr/9H2AVOynrIU 메타버스 Metaverse
    https://search3.kakaocdn.net/argon/0x200_85_hr/8sN9XZ1WiE1 메타버스 관련주
    https://search3.kakaocdn.net/argon/0x200_85_hr/EpuqnF1p3xC &apos;Z세대 흐름&apos; 메타 
    버스 읽는 사람들..미래 지향 전망서 인기
    https://search4.kakaocdn.net/argon/0x200_85_hr/9NzYTXoutoN 메타버스
    https://search4.kakaocdn.net/argon/0x200_85_hr/3XZqcyEQlmy 메타버스 뜻
    https://search4.kakaocdn.net/argon/0x200_85_hr/2VECAiHgHF3 메타버스의 기본개념과 종류를
    알아보자. 증강현실. 라이프로깅.
    https://search3.kakaocdn.net/argon/0x200_85_hr/F4kbRJkw8T3 메타버스 Metaverse
    https://search4.kakaocdn.net/argon/0x200_85_hr/3V7f8yxoz8Z 한화시스템, 메타버스 플랫폼 
    에서 신입·경력 개발자 면접 ....

    '''

- r.html.render() 한 문장 추가한 것 뿐인데, 데이터를 모두 가져온 것을 볼 수 있다.


good4me.co.kr


이제, 이미지 원본을 가지러 가볼 것이다.

r1.html.find('div#imgList > div.wrap_thumb > a')
print(len(img_list))  # 80

- img 태그 바로 위 a 태그에 링크된 주소가 원본 이미지를 보여주는 페이지인데, 문제는 펼침으로 이미지를 보여주기 때문에 그 페이지에서 다시 원본 링크를 찾아야 한다.

펼친 원본 이미지

- 메타버스 관련 이미지 80개 나온 img_list가 리스트 타입이기 때문에 for 문으로 확인을 해보면, 별도의 <img src=....> 태그로 이미지가 링크되어 있다.

원본 이미지 링크 주소

 

 

Daum 이미지 다운로드 소스 코드

from requests_html import HTMLSession
from urllib.parse import urljoin
import os

def daumImage_scraping(keyword):
    url = f'https://search.daum.net/search?w=img&q={keyword}&DA=IIM'

    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
            (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36',
    } 

    session = HTMLSession()
    r1 = session.get(url, headers=headers)

    r1.html.render()
    # print(r1.text)
    # print(r1.html.html)  # 렌더링 부분을 html로 확인할 경우

    # ## 스크롤을 하고 싶다면...
    # r1.html.render(scrolldown=5000)  # scrolldown value = pixel

    img_list = r1.html.find('div#imgList > div.wrap_thumb > a')

    print(len(img_list))  # 80

    if not os.path.exists('daum_images'):
        os.mkdir('daum_images')
    
    imgCount = 1
    for img in img_list:
        img_src = img.attrs['href']
        img_src = urljoin(url, img_src)
        # print(img_src)

        r2 = session.get(img_src, headers=headers)
        r2.html.render()
        # print(r2.html.html)
        img_res = r2.html.find('#ins_img_viewer_big_img_org')
        # print(len(img_res))  # 1

        img_url = img_res[0].attrs["src"]
        print(img_url)

        file_name = str(imgCount).zfill(3) + '_' + img_url.split('/')[-1]
        print(file_name)
        imgCount += 1

        ## 이미지 다운로드
        with open('./daum_images/' + file_name, 'wb') as f:
            f.write(session.get(img_url, headers=headers).content)

        if imgCount > 10:
            break

daumImage_scraping('메타버스')

- for 문으로 한 번에 다운로드 가능한 이미지는 80개인데, 이미지 스크롤을 하고 싶다면, scrolldown= 속성을 주어서 스크롤을 내릴 수 있다.

- r1.html.render(scrolldown=5000) 코드로 스크롤 후 확인해보니 320개까지 찾아준다.

- 그리고, 그 이후는 '펼쳐보기' 버튼이 있다. 

펼쳐보기 버튼

- 이 부분에 대해서는 자료를 찾아보아야 해결 여부를 판단할 수 있을 것 같다. (찾으면 내용 추가..)

 

주의할 것은,

각각의 이미지에도 경고문구가 있듯이 이미지는 저작권 문제가 있으니 항상 주의하고,

무리한 이미지 다운로드는 서버에 악영향을 준다는 점,

그로 인해 다른 문제(?)도 발생할 수 있으니 스크래핑(크롤링)은 항상 조심을 해야....

 

댓글