나도 코딩님의 파이썬 웹 스크래핑 강의 정리
https://www.youtube.com/watch?v=yQ20jZwDjTE
1. 기초 지식
웹 스크래핑과 크롤링의 차이
- 웹 스크래핑: 웹페이지에서 내가 필요한 내용만 가져오는 것
- 웹 크롤링: 특정 웹사이트를 돌아다니며 모든 정보들을 수집하는것
XPath
특정 element의 긴 전체 경로(ex. /html/body/div/span/div...) 대신 표시하는 Unique하고 요약된 경로
크롬 브라우저의 개발자도구에서 특정 element를 우클릭/copy/Copy XPath로 XPath 값을 얻어낼 수 있다.
lib. requests
pip install requests
raise_for_status(): 200대 응답이 아니면 에러를 출력하고 프로그램을 중단해준다.
import requests
res = requests.get("http://naver.com")
res.raise_for_status()
print(res.text)
텍스트 파일로 만들 수 있다.
with open("test.txt", "w", encoding="utf-8") as f:
f.write(res.text)
정규식
이미 다른 글에서 배웠으나 여기서 간단하게만 다시 다룬다.
https://whitepro.tistory.com/245
p = re.compile("ca.e")
여기서 .은 하나의 문자를 의미한다. ^는 문자열의 시작을 의미한다.
ex) ^de : desk, destination (O), fade (X)
대표적인 메서드
- match : 문자열의 처음부터 일치여부 확인 p.match("careless") -> care (O)
- search : 문자열 중 일치하는게 있는지 확인 p.seart("good care") -> care (O)
- group : 일치하는 문자열 반환
- string: 입력받은 문자열
- start: 일치하는 문자열의 시작 index
- end: 일치하는 문자열의 끝 index
- span: 일치하는 문자열의 시작/끝 index를 함께 표시
- findall: 일치하는 모든 항목을 리스트로 반환
User Agent
헤더에 User Agent 정보가 없으면 각 사이트에서 요청을 막을 수도 있다. User-Agent 정보는 서버에 요청을 하는 주체가 누구인지 알려주는 역할을 한다.
강의 내용처럼 What is my User Agent를 검색하여 해당 페이지에서 user agent 헤더값을 복사해오면 된다.
또는 개발자도구를 켜놓고 아무 사이트에나 접속하여 Header를 확인해보면 본인의 user-agent 정보를 얻을 수 있다.
그리고 아래처럼 headers에 User-Agent 정보를 넘겨주면 Tistory와 같이 User-agent 정보가 없으면 접근을 막는 사이트에도 403 에러가 나지않고 접근이 가능하다.
import requests
url = "http://whitepro.tistory.com"
headers = {
"User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}
res = requests.get(url, headers = headers)
res.raise_for_status()
with open("test.html", "w", encoding="utf-8") as f:
f.write(res.text)
2. Beautifulsoup
이제 Beautifulsoup 라이브러리를 통해 실제 웹스크래핑을 수행한다. 다양한 웹사이트에서 실습을 해본다. lxml은 코드 구문들을 분석하는 parser이다.
pip install beautifulsoup4
pip install lxml
기본 코드
import requests
from bs4 import BeautifulSoup
url = "http://whitepro.tistory.com"
headers = {
"User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}
res = requests.get(url, headers=headers)
res.raise_for_status()
soup = BeautifulSoup(res.text, "lxml")
print(soup.a)
- "lxml" 인자값은 parser 종류를 lxml로 하겠다는 것이다.
- soup.a는 bs4로 처리한 결과 중 a 태그를 갖는 맨 처음 요소를 가져오겠다는 의미이다.
기본 문법들
- soup.a.attrs : 해당 태그의 속성값들 반환
- soup.find("li", attrs={"class":"rank01"}) : li 태그를 갖는 요소 중 rank01 클래스인 항목 반환
- list 형태로 되어있을 땐, 위 결과에 .next_sibling, .previous_sibling을 chaining 방식으로 사용하여 형제 요소들을 불러올 수 있다.
- .find_next_sibling("li") : 결과 다음의 요소 중 li 태그를 갖는 요소를 찾아온다.
- .find_next_siblings("li") : 결과 다음의 요소 중 lit 태그를 갖는 모든 요소를 찾아온다.
- .find("a", text="abcde") : a 태그 중 텍스트값이 "abcde"인 요소를 찾아온다.
- 부모 요소는 .parent로 불러올 수 있다.
- .get_text(): 해당 태그 요소의 텍스트값만 가져온다.
- .find_all("a", attrs={"class": "title"}) : 해당 태그(a), 클래스(title)를 갖는 모든 요소를 list 형태로 불러온다.
3. 여러 예제들
이미지 파일 다운로드 받기
이미지 파일을 다운로드 받는 작업을 할려면 위에서 배운 내용에 아래 내용을 추가하는 방식으로 작업하면 된다.
- 파일 확장자는 각 사이트에서 제공하는 방식으로 처리해야한다. 여기서는 jpg
- 이미지는 binary로 제공되기 때문에 "wb"를 입력한다.
- image_res.content로 실제 바이너리 내용들을 불러올 수 있다.
# BeautifulSoup을 통해 images을 얻어오고 나서 아래 작업을 한다.
for idx, image in enumerate(images):
image_url = image["src"]
image_res = requests.get(image_url)
image_res.raise_for_status()
with open(f"file{idx+1}.jpg", "wb") as f:
f.write(image_res.content)
CSV 파일로 데이터 받아오기
기본적으로 url 및 element를 분석하여 beautifulsoup으로 처리하는 부분은 위에서 배운 부분들과 같다. 파일 처리하는 부분만 다르다.
- newline=""으로 처리해줘야 각 line마다 불필요한 한 줄 띄우기(\n)가 생략된다.
- 엑셀로 open시 한글이 깨지면 encoding을 utf-8-sig로 설정해줘야한다. 기본적으로는 "utf8"만 입력 가능
f = open(filename, "w", encoding="utf-8-sig", newline="")
writer = csv.writer(f)
for page in range(1, 10):
# url과 속성값을 이용하여 데이터 찾아오기. 중략
title = "N 종목명 현재가 ...".split("\t")
writer.writerow(title)
# 중략
writer.writerow(data)
'Programming-[Backend] > Python' 카테고리의 다른 글
웹 스크래핑, 크롤링- 2. Selenium (0) | 2023.03.01 |
---|---|
[링크] 파이썬 가상환경 venv, Pycharm (0) | 2023.02.27 |
[TIL] python locale, OS의 locale (0) | 2023.02.13 |
[링크] python circular import 해결 - import time, runtime (0) | 2023.01.19 |
[TIL][링크] 파이썬 부모 생성자 호출, __init__ BaseError 상속 (0) | 2023.01.02 |