1. 기본 설치 파일 및 코드
먼저 requests 와 beautifulsoup를 설치합니다.
pip install requests
pip install beautifulsoup4
naver.py로 파이썬 파일을 만들어 아래 코드를 입력합니다.
import requests
from bs4 import BeautifulSoup
url = "https://www.naver.com/"
req = requests.get(url)
html = req.text
soup = BeautifulSoup(html,"html.parser") # html을 html_parser로 분석한다
2.사람이 접속한 것처럼 보이게 하기
접속한 사이트에 접속하여 개발자 도구를 실행합니다(예시로는 네이버를 사용하지만 다른 사이트라도 상관없습니다.)
개발자 도구의 네트워크 탭을 클릭한 후 F5를 눌러 새로고침을 합니다.
그리고 가장 위의 url 주소를 클릭하면 아래와 같은 화면이 나타납니다.
위의 빨간색 네모박스의 User-Agent를 복사합니다.
requests의 여러 기능들 중 headers를 찾는 기능도 있습니다.
print(req.request.headers)
파이썬에서 위 코드를 작성하고 실행하면 아래와 같이 나올 것입니다.
즉 아무런 설정없이 get(url)을 보내게 되면 파이썬으로 실행했다는 정보를 보낸다는 것입니다.
따라서 아래 코드를 추가합니다.
headers ={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
}
그리고 req 변수를 변경합니다.
req = requests.get(url,headers=headers)
실행을 시켜보면 아래와 같이 변경된 것을 확인할 수 있습니다.
3.원하는 경로를 입력하여 URL 이동하기
먼저 네이버에서 검색을 합니다 저는 뉴진스를 검색했습니다.
주소창을 보시면 query 뒤에 검색 내용이 입력되는 것을 확인할 수 있습니다.
url을 전부 복사합니다.
파이썬 코드에서 url을 변경합니다
url = "https://search.naver.com/search.naver?where=view&sm=tab_jum&query=%EB%89%B4%EC%A7%84%EC%8A%A4"
그대로 복사해서 붙여넣었지만 한글부분이 위와 같이 알아볼수 없는 언어로 적힐 것입니다.
그러나 걱정하실것없이 해당 내용을 지우고 코드를 수정하겠습니다.
url을 base_url로 변경하고 입력란을 추가하겠습니다. 즉 아래와 같이 코드를 수정하겠습니다.
base_url = "https://search.naver.com/search.naver?where=view&sm=tab_jum&query="
keyword = input("검색어를 입력하세요: ")
url = base_url+keyword
print(url)
해당 내용을 실행하겠습니다. 손흥민을 검색하니 아래와 같이 나타나는 것을 볼 수 있습니다.
url을 전부 복사해서 크롬창의 url에 붙여넣기하면 view탭의 검색내용은 손흥민으로 가는 것을 볼 수 있습니다.
VSCODE에서는 하이퍼링크가 바로 생성된다고 들었는데 파이참에서는 검색내용을 포함한 하이퍼링크가 생성되지는 않았습니다.
4.정보 가져오기
네이버의 view 탭에서 정보를 가져와보겠습니다
뉴진스를 검색해서 개발자 코드를 열어보시면 제목부분에 아래와 같은 클래스로 되어있는 것을 볼 수 있습니다.
여러내용을 검색해서 공통된 부분을 찾는 것이 좋습니다.
해당 클래스를 전부 찾는 코드를 추가합니다.
html = req.text
soup = BeautifulSoup(html,"html.parser") # html을 html_parser로 분석한다
result = soup.select(".api_txt_lines.total_tit")
#selectone이 아닌 select는 해당 클래스를 전부 가져온다. select내부는 클래스명이며 띄어쓰기가 되어있으면 .으로 대체해준다.
print(result)
코드를 작성했으면 실행하겠습니다.
view 제목들을 가져오는 것을 확인할 수 있습니다.
해당 코드를 반복문으로 출력해보겠습니다. result 코드를 복수형으로 변환하고 for반복문을 추가합니다.
results = soup.select(".api_txt_lines.total_tit")
#selectone이 아닌 select는 해당 클래스를 전부 가져온다. select내부는 클래스명이며 띄어쓰기가 되어있으면 .으로 대체해준다.
for result in results:
print(result)
print() #알아보기 쉽게 빈줄 추가
아래와 같이 출력되는 것을 확인할 수 있습니다.
태그없이 내용만 출력하고 싶다면 result변수에 .text를 추가하면됩니다.
for result in results:
print(result.text)
print() #알아보기 쉽게 빈줄 추가
결과는 아래와 같이 출력됩니다.
해당 내용을 접속할 url을 찾고 싶다면 아래와 같이 코드를 추가하면 됩니다.
for result in results:
print(result['href'])
print(result.text)
print() #알아보기 쉽게 빈줄 추가
또는
for result in results:
print(result.get('href'))
print(result.text)
print() #알아보기 쉽게 빈줄 추가
아래와 같이 접속할 수 있는 경로가 나타납니다.
5. 여러 정보를 한번에 가져오기
1) zip 사용
이번엔 제목과 작성자를 가져오겠습니다. 그리고 아래와 같이 코드를 수정합니다.
titles = soup.select(".api_txt_lines.total_tit")
#selectone이 아닌 select는 해당 클래스를 전부 가져온다. select내부는 클래스명이며 띄어쓰기가 되어있으면 .으로 대체해준다.
names = soup.select(".sub_txt.sub_name")
for result in zip(names,titles): #zip 함수는 여러변수를 묶어서 튜플로 만들어준다.
print(result[0].text) # names 정보
print(result[1].text) # titles 정보
print() #알아보기 쉽게 빈줄 추가
출력하면 아래와 같은 결과가 나타납니다.
다만 주의해야 할점은 zip함수를 사용했을 때 작성자나 제목이 없는 list가 있다면 해당 수만큼 밀리는 경우가 발생합니다.
2) 공통된 상위태그를 사용
먼저 아이유를 검색하여 개발자도구를 열어보겠습니다.
이번에는 박지성을 검색하여 개발자 도구를 열어보겠습니다
아이유는 timeline_area 이지만 박지성은 total_area로 나오는 것을 볼 수 있습니다. 물론 박지성을 검색해도 timeline_area로 나올때도 있습니다.
저 두개의 상황이 나온다고 가정했을 때 코드를 수정하겠습니다.
total_area = soup.select(".total_area")
timeline_area = soup.select(".timeline_area")
if total_area:
areas = total_area
elif timeline_area:
areas = timeline_area
else:
print("확인요망")
for area in areas:
title = area.select_one(".api_txt_lines.total_tit") # select_one은 하나만 가져오는 것
name = area.select_one(".sub_txt.sub_name")
print(name.text)
print(title.text)
print()
위의 두 상황외의 상황이 존재한다면 '확인요망'이라는 글자가 나타날 것이므로 케이스를 추가해주면 됩니다.
6.광고 제거하기
광고 요소의 클래스를 찾아서 반복문 부분을 아래처럼 수정합니다.
for area in areas:
ad = area.select_one(".link_ad") #광고요소의 클래스
if ad:
print("광고")
continue
title = area.select_one(".api_txt_lines.total_tit") # select_one은 하나만 가져오는 것
name = area.select_one(".sub_txt.sub_name")
print(name.text)
print(title.text)
print()
7.동적타입에서의 beatifulsoup
beatifulsoup애서는 검색 당시의 정보를 가져오기때문에 네이버 처럼 스크롤시 정보가 더 생성되는 동적타입에서는 모든 정보를 가져올 수 없습니다.
이는 태그의 개수로 확인해 볼 수 있습니다.
처음 검색했을 때 total_area태그의 개수를 확인해보겠습니다.
빨간색 네모상자를 보시면 총 30개의 태그가 있습니다.
그러면 스크롤을 내린 후 다시 확인해보겠습니다.
이번엔 60개로 늘어난 것을 확인할 수 있습니다.
그러면 코드상에서는 몇개가 출력되는지 확인해보겠습니다.
print(len(areas))
30개가 출력되는 것을 확인할 수 있습니다.
즉 동적태그는 beautifulsoup로 크롤링 할 수 없기 때문에 셀레니움을 사용해야합니다.
8. 사용예제
자세한 사용방법은 주석을 확인하시면 됩니다. 현재 네이버에서는 BeautifulSoup만으론 크롤링이 안되고 셀레니움을 병행해야 합니다.
1) 네이버 검색
import requests
from bs4 import BeautifulSoup
url = "https://www.naver.com/"
headers ={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
}
req = requests.get(url,headers=headers)
html = req.text
soup = BeautifulSoup(html,"html.parser")
print(soup.title) # 타이틀 태그를 찾는다.
print(soup.h1) # h1 태그를 찾는다.
print()
h1 = soup.find('h1') # h1태그를 찾아 h1변수에 저장한다.
print("h1: "+str(h1)) #문자열을 더했을 때는 str로 감싸준다.
print()
h1 = soup.select_one('h1') # h1태그를 찾아 h1변수에 저장한다.
print(h1)
print()
h2 = soup.find(class_='search_logo') # search_logo라는 클래스를 찾아 h2변수에 저장한다.
print("h2: "+str(h2))
print()
h3 = soup.find(id='special-input-logo') # id가 special-input-logo인 값을 찾아 h3에 저장한다.
print("h3: "+str(h3))
print()
service_name = soup.find(class_='service_name',string='증권') #class가 link_service이면서 문자열은 증권인 값을 가져온다.
#현재 네이버에서는 사용이 안됨 -> 셀레니움과 혼용하면 사용가능
service_name_a = soup.find('a',string='증권') # a태그이면서 문자열은 증권인 값을 가져온다.
#현재 네이버에서는 사용이 안됨 -> 셀레니움과 혼용하면 사용가능
print(service_name_a)
service_name_all = soup.find_all(class_='service_name') # service_name란 클래스를 가진 모든 값을 가져온다.
print(service_name_all)
print(len(service_name_all))
for service in service_name_all:
print(service.text)
print(service['href'])
print()
2) melon 차트
import requests
from bs4 import BeautifulSoup
url = "https://www.melon.com/chart/index.htm"
# "javascript:melon.link.goAlbumDetail('11286070');"
# a태그의 자바스크립트 안의 숫자를 가져오는 함수
def get_song_nums(song_num_text):
# song_num=[]
# for num in song_num_text:
# if num.isdigit(): # num이 숫자인지 판단
# song_num.append(num)
# song_num = "".join(song_num) # 리스트를 결합
#
song_num = "".join([num for num in song_num_text if num.isdigit()]) # 리스트 컴프리헨션 -> 위 주석내용을 한줄로
return song_num
headers ={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
}
req = requests.get(url,headers=headers)
html = req.text
soup = BeautifulSoup(html,"html.parser")
##### 방법1 #######
# lst50 = soup.select(".lst50")
#
# lst100 =soup.select(".lst100")
#
# lst = lst50+lst100
##### 방법2 #######
# lst = soup.select(".lst50, .lst100") # 위 주석처리된 내용은 이와같이 처리 가능
##### 방법3 #######
lst = soup.find_all(class_=["lst50","lst100"])
for rank,i in enumerate(lst,1):
title = i.select_one(".ellipsis.rank01 a") # ellipsis rank01클래스 아래의 a태그를 찾는다.
singer = i.select_one(".ellipsis.rank02 > a") # ellipsis rank02 클래스 바로 아래의 a태그를 찾는다.
singer_link = get_song_nums(singer['href']) # singer에서 href 속성을 가져온다.
album = i.select_one(".ellipsis.rank03 > a")
album_link = get_song_nums(album['href'])
print(f"{rank} : {title.text}")
print(f"{singer.text} : https://www.melon.com/artist/timeline.htm?artistId={singer_link}")
print(f"{album.text} : https://www.melon.com/album/detail.htm?albumId={album_link}")
3) 다음뉴스
import requests
from bs4 import BeautifulSoup
url = "https://news.daum.net/"
headers ={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
}
req = requests.get(url,headers=headers)
html = req.text
soup = BeautifulSoup(html,"html.parser")
item_issues = soup.select(".item_issue")
for item in item_issues:
# 언론사
#### 방법1 ###
# press = item.select(".thumb_g")[1]["alt"]
#### 방법2 ###
press = item.select_one(".logo_cp img")["alt"] #
category = item.select_one(".txt_category").text
link_txt = item.select_one(".link_txt")
link = link_txt['href']
txt = link_txt.text.strip() # 맨앞과 맨끝의 공백제거
print(f"{press} - {category}")
print(f"{txt} : {link}")
4) ssg.com 이벤트 정보 가져오기
import requests
from bs4 import BeautifulSoup
url = "https://www.ssg.com/event/eventMain.ssg"
headers ={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
}
req = requests.get(url,headers=headers)
html = req.text
soup = BeautifulSoup(html,"html.parser")
li = soup.select_one(".evt_osmu_lst") #해당 클래스에서 여러건이 있을 때 select_one을 하면 가장 첫번째 값만 가져온다.
units = li.select(".eo_link")
for unit in units:
link = unit["href"]
if link.startswith("https"):
print(link)
else:
print(f"https://event.ssg.com{link}")
eo_in = unit.select_one(".eo_in")
text_list = eo_in.find_all(string=True) # string=True 는 string이 있는 것을 가져오라는 뜻
for text in text_list:
if text != "\n":
print(text)
print()
5) cgv 정보 가져오기
import requests
from bs4 import BeautifulSoup
url = "http://www.cgv.co.kr/movies/"
headers ={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
}
req = requests.get(url,headers=headers)
html = req.text
soup = BeautifulSoup(html,"html.parser")
sect_movie_chart= soup.select_one(".sect-movie-chart")
movie_chart = sect_movie_chart.select("li")
for rank,movie in enumerate(movie_chart,1):
title = movie.select_one(".title")
score = movie.select_one(".score")
ticketing = score.select_one(".percent")
egg_gage = score.select_one(".egg-gage.small > .percent")
info = movie.select_one(".txt-info > strong").next_element # txt-info 안에 있는 strong 태그에서 텍스트인지, 태그인지 상관없이 바로 다음 요소만 가져온다. 예) <strong>문자열1<span>문자열2</span></strong> -> 문자열1만 출력
print(f"<<<{rank}>>>")
print(title.text)
print(ticketing.get_text(" : ")) # 텍스트로 가져온 문자열이 포함되어 있는 태그가 있다면 둘 사이를 연겷해줄 수 있다. 예) <td>문자열1<span>문자열2</span></td> 일때 문자열1 : 문자열2
print(egg_gage.text)
print(f"{info.strip()} 개봉")
print()
6)쿠팡 정보 가져오기
쿠팡은 크롤링을 자주하면 접속이 막히게 되므로 많이 하지 않는 것이 좋습니다.
import requests
from bs4 import BeautifulSoup
base_url = "https://www.coupang.com/np/search?component=&q="
keyword = input("검색어를 입력하세요: ")
url = base_url+keyword
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7"
}
cookie = {"a":"b"} # 아무 의미없는 쿠키를 넣는다.
req = requests.get(url,timeout=5,headers=headers,cookies=cookie) # tiemout 은 대기시간 설정하는 것
# print(req.status_code) # 접속 가능한지 상태확인
html = req.text
soup = BeautifulSoup(html,"html.parser")
items = soup.select("[class=search-product]") # class가 search-product인것만 찾는다.
rank =1
for item in items:
# print(item['class']) # class 속성을 가져온다.
badge_rocket = item.select_one(".badge.rocket")
if not badge_rocket:
continue
name = item.select_one(".name")
price = item.select_one(".price-value")
thumb = item.select_one(".search-product-wrap-img")
link = item.a['href'] # item 요소 하위에 있는 a태그의 href 속성을 가져온다.
print(f"{rank}위")
print(name.text)
print(f"{price.text}원")
print(f"https://coupang.com{link}")
if thumb.get("data-img-src"):
img_url = f"http:{thumb.get('data-img-src')}"
else:
img_url = f"{thumb.get('src')}"
print(img_url)
print()
img_req = requests.get(img_url)
with open(f"upload/{rank}.jpg","wb") as f: #upload 폴더안에 1.jpg,2.jpg .. 형태로 저장
f.write(img_req.content) # 파일 내용 다운로드
rank +=1
# print(len(items))
'PYTHON Programming > Python' 카테고리의 다른 글
[python] selenium 웹 드라이버 옵션 추가 (0) | 2024.05.22 |
---|---|
[python] 웹크롤링(selenium) (0) | 2024.05.21 |
[python] 설치된 패키지 목록 생성과 requirements.txt 속 패키지 설치 (0) | 2024.05.21 |
[python] 외장함수 (0) | 2024.05.21 |
[python] 내장함수 (0) | 2024.05.21 |