크롤링보다는 자동화 쪽에 좀 더 관심이 있음.
17. BeautifulSoup 사용법 및 간단 웹 파싱 기초 (2)
- html 파일 파싱 연습
- 더욱 다양한 css 선택자 사용해보기
- find, select 실습
http://pythonstudy.xyz/python/article/401-정규-표현식-Regex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from bs4 import BeautifulSoup
import sys
import io
import re #regex
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
html = """
<html>
<body>
<ul>
<li><a id="naver" href="http://www.naver.com">naver</a></li>
<li><a href="http://www.daum.net">daum</a></li>
<li><a href="http://www.daum.com">daum</a></li>
<li><a href="https://www.google.com">google</a></li>
<li><a href="https://www.tistory.com">tistory</a></li>
</ul>
</body>
</html>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.find(id="naver").string)
li = soup.find_all(href=re.compile(r"^https://"))
for e in li:
print(e.attrs['href'])
- 정규표현식을 사용할수도 있음. 활용율이 좀 떨어짐
- css 선택자를 더 많이 사용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from bs4 import BeautifulSoup
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
fp = open('food-list.html', encoding="utf-8")
soup = BeautifulSoup(fp, "html.parser")
# print("1", soup.select_one("li:nth-of-type(8)").string) # 제대로 안됨
print("2", soup.select_one("#ac-list > li:nth-of-type(4)").string)
print("3", soup.select("#ac-list > li[data-lo='cn']")[0].string)
print("4", soup.select("#ac-list > li.alcohol.high")[0].string)
param = {"data-lo": "cn", "class": "alcohol"}
print("5", soup.find("li", param).string)
print("6", soup.find(id="ac-list").find("li", param).string)
for ac in soup.find_all("li"):
if ac['data-lo'] == 'us':
print('data-lo == us', ac.string)
- css 선택자 사용하는 방법 연습
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from bs4 import BeautifulSoup
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
fp = open('cars.html', encoding="utf-8")
soup = BeautifulSoup(fp, "html.parser")
def car_func(selector):
print("car_func", soup.select_one(selector).string)
car_func("#gr")
car_func("li#gr")
car_func("ul > li#gr")
car_func("#cars #gr")
car_func("#cars > #gr")
car_func("li[id='gr']")
print("car_func", soup.select("li")[3].string)
print("car_func", soup.find_all("li")[3].string)
- 함수 하나 만들어서 선택자 사용
1
2
3
4
5
6
7
8
car_lambda = lambda q : print("car_lambda", soup.select_one(q).string)
car_lambda("#gr")
car_lambda("li#gr")
car_lambda("ul > li#gr")
car_lambda("#cars #gr")
car_lambda("#cars > #gr")
car_lambda("li[id='gr']")
- 람다식 사용 가능
- https://thrillfighter.tistory.com/356
18. BeautifulSoup 사용법 및 간단 웹 파싱 실습(1) - 네이버, 다음, 인프런
- 다음 금융 시가총액 상위 종목 가져오기
- 네이버 금융 탑 10 종목 가져오기
- 인프런 추천 강좌 10개 가져오기
위 3개의 공통점은 값이 자주 바뀜. 매일-매주-매월 일정한 시간에 데이터를 가져와서 활용가능.
자동화를 해서 업무의 효율성 증가할 수 있음
다음 금융
- https://finance.daum.net/
-
다음 페이지의 구조가 바뀌어 기존 코드는 동작하지 않음.
-
-
- 29 이후로 다음 금융 사이트 파싱 예제가 ajax 비동기 방식으로 변경.
-
-
fake-useragent 플러그인 필요
1
pip install fake-useragent
- user agent 정보를 점검해서 크롤링 봇일 경우에는 정보를 주지 않는 사이트의 경우에 사용
-
user agenet 정보를 headers에 추가해서 전달함.
- 크롬 개발자 도구에서 headers 값 확인 (xhr 버튼 클릭 필터 후 확인)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from bs4 import BeautifulSoup
import urllib.request as req
import sys
import io
import json
from fake_useragent import UserAgent
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
# Fake Header 정보
ua = UserAgent()
# 헤더 선언
headers = {
'User-Agent': ua.ie,
'referer': 'https://finance.daum.net/'
}
# 다음 주식 요청 URL
url = "https://finance.daum.net/api/search/ranks?limit=10"
res = req.urlopen(req.Request(url, headers=headers)).read().decode('utf-8')
soup = BeautifulSoup(res, "html.parser")
# 응답 데이터 확인(Json Data)
print('res', res)
# 응답 데이터 str -> json 변환 및 data 값 저장
rank_json = json.loads(res)['data']
# 중간 확인
print('중간 확인 : ', rank_json, '\n')
for elm in rank_json:
# print(type(elm)) #Type 확인
print('순위 : {}, 금액 : {}, 회사명 : {}'.format(elm['rank'], elm['tradePrice'], elm['name']), )
네이버 금융
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from bs4 import BeautifulSoup
import urllib.request as req
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
url = "https://finance.naver.com/sise/"
res = req.urlopen(url).read().decode('cp949')
soup = BeautifulSoup(res, "html.parser")
top10 = soup.select("#siselist_tab_0 > tr")
i = 1
for e in top10:
if e.find("a"): # if e.find("a") is not None:
print(i, e.select_one(".tltle").string)
i += 1
- 테이블로 되어있는것은 조금 생각을 해봐야함.
- 다른점을 찾기
인프런
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from bs4 import BeautifulSoup
import urllib.request as req
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
url = "https://www.inflearn.com/"
res = req.urlopen(url).read().decode("utf-8")
soup = BeautifulSoup(res, "html.parser")
recommnad = soup.select(".welcome_content .card-content>.course_title")
# print(recommnad)
for i, e in enumerate(recommnad, 1):
print(i, e.string)
# href 가져오기
link = soup.select(".welcome_content .card.course.course_card_item")
for i, e in enumerate(link, 1):
if e.select_one('a'):
print(e.select_one('a')['href'])
- 사이트 구조가 달라짐.
- 여기서 시작해보세요 정도 가져오는 걸로..
실습: 다음 실시간 인기 검색어 + link 스크랩핑 해오기
- 실시간 검색어 폐지로 작업 x
19. BeautifulSoup 사용법 및 간단 웹 파싱 실습(2) - 네이버, 인프런
- 네이버에서 원하는 사진(이미지) 한 번에 다운로드 하기
- 인프런 추천 강좌 이미지 한 번에 다운로드 & 제목 텍스트 파일 출력하기
ErrorCode: https://python.readthedocs.io/en/latest/library/errno.html
데이터의 양, 다양성, 속도가 중요함 (3vs)
네이버에서 원하는 사진(이미지) 한번에 다운로드 하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from bs4 import BeautifulSoup
import urllib.request as req
import urllib.parse as rep
import sys
import io
import os
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
opener = req.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
req.install_opener(opener)
base = "https://search.naver.com/search.naver?where=image&sm=tab_jum&query="
quote = rep.quote_plus("사자")
url = base + quote
res = req.urlopen(url)
savePath = "C:\\imagedown\\" # c:\imagedown\
# 예외처리
try:
if not (os.path.isdir(savePath)):
os.makedirs(os.path.join(savePath))
except OSError as e:
if e.errno != errno.EEXIST:
print("폴더 만들기 실패!")
raise
soup = BeautifulSoup(res, "html.parser")
# 크롬의 copy selector 등으로 가져와서 참고 후 수정 가능
img_list = soup.select("div.img_area > a.thumb._thumb > img")
# print("test", img_list)
for i, img_list in enumerate(img_list, 1):
# print(img_list['data_source'])
fullFileName = os.path.join(savePath, savePath+str(i)+'.jpg')
req.urlretrieve(img_list['data_source'], fullFileName)
print('다운로드 완료')
- 네이버에서 크롤링을 막아둬서 해당 코드 동작 안함.
- 셀라리늄 같은 걸 사용해서 크롤링을 해야 될 것으로 보임.
인프런 추천 강좌 이미지 한 번에 다운로드 & 제목 텍스트 파일 출력하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from bs4 import BeautifulSoup
import urllib.request as req
import urllib.parse as rep
import sys
import io
import os
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
base = "https://www.inflearn.com/courses"
quote = rep.quote_plus("")
url = base + quote
res = req.urlopen(url)
savePath = "C:\\imagedown\\" # c:\imagedown\
# 예외처리
try:
if not (os.path.isdir(savePath)):
os.makedirs(os.path.join(savePath))
except OSError as e:
if e.errno != errno.EEXIST:
print("폴더 만들기 실패!")
raise
soup = BeautifulSoup(res, "html.parser")
img_list = soup.select(".course_card_item")
for i, e in enumerate(img_list, 1):
with open(savePath+"text_"+str(i)+".txt","wt") as f:
f.write(e.select_one(".course_title").string)
fullFileName = os.path.join(savePath, savePath+str(i)+'.png')
req.urlretrieve(e.select_one(".image > img")['src'], fullFileName)
print('다운로드 완료')
- 강좌 내용이랑 좀 다른 부분이 있어 헤맴.
- 파이썬 에러 처리 서치 필요.
- enumerate 서치 필요
실습(과제): 인프런 추천강좌(평점순 강좌, 학생수순) 이미지, 텍스트 가져오기
- 사이트 구조 변경으로 실습 불가
20. 파이썬 기초 공부 - 파이썬 클래스(Class) 개념 알아보기
- 클래스 생성자 이해하기
- self 이해하기
- 클래스 네임스페이스 이해하기
- 클래스 변수와 인스턴스 변수 차이점 이해하기
Class Documentation: https://docs.python.org/3/tutorial/classes.html
네임스페이스라는 것은 변수가 객체를 바인딩할 때 그 둘 사이의 관계를 저장하고 있는 공간을 의미합니다.
객체 - 자동차
클래스 (Class)
- 필드(속성,변수)
- 메서드(동적-작업을수행)
자동차
- 속성(변수): 색, 배기량, 자동(수동), 중형소형
- 메서드: 전진, 후진, 왼쪽, 오른쪽
클래스 생성자 이해하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
class UserInfo:
def __init__(self, name, phone):
self.name = name
self.phone = phone
def print_info(self):
print("-------------")
print("Name: " + self.name)
print("phone: " + self.phone)
print("-------------")
def __del__(self):
print("delete!")
# 인스턴스 화
user1 = UserInfo("kim", "010-1111-2222")
user2 = UserInfo("park", "010-5555-6666")
# 주소값 확인
print(id(user1))
print(id(user2))
user1.print_info()
user2.print_info()
# 파이선에서 제공하는 dict
print(user1.__dict__)
print(user2.__dict__)
print(user1.phone, user1.name)
Self 이해하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
class SelfTest:
def function1():
print("function1 called!")
def function2(self):
print(id(self))
print("function2 called!")
f = SelfTest()
# print(dir(f))
print(id(f))
f.function2()
print(SelfTest.function1())
- 자동으로 Self 넘겨짐
- 파이썬 메서드 호출 방법 2개 (Self 입력 안할시 클래스명.메서드명)
클래스 변수, 인스턴스 변수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
# 클래스 변수, 인스턴스 변수
class Warehouse:
stock_num = 0 # 클래스 변수
def __init__(self, name):
self.name = name # 인스턴스 변수
Warehouse.stock_num += 1
def __del__(self):
Warehouse.stock_num -= 1
user1 = Warehouse('kim')
user2 = Warehouse('park')
print(user1.name)
print(user2.name)
print(user1.__dict__) # 인스턴스의 네임스페이스 확인
print(user2.__dict__)
print(Warehouse.__dict__) # 클래스의 네임스페이스 확인
print(user1.stock_num) # 처음엔 자기 자신의 네임스페이스 확인 후 없으면 클래스의 네임스페이스 확인
print(user2.stock_num)
- 인스턴스의 네임스페이스를 찾고 없으면 클래스의 네임스페이스를 찾음
- 클래스의 변수는 공유가 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
class NameTest:
total = 0
print(dir())
print("before : ", NameTest.__dict__)
NameTest.total = 1
print("after : ", NameTest.__dict__)
n1 = NameTest()
n2 = NameTest()
print(id(n1), " vs ", id(n2))
print(dir())
print(n1.__dict__) # {}
print(n2.__dict__) # {}
n1.total = 77
print(n1.__dict__) # 인스턴스 네임스페이스에 total이 생김
print(n1.total) # 77
print(n2.total) # 1
- dir()은 전체 프로그램의 구조를 보여줌
__dict__
는 해당 클래스 및 인스턴스의 네임스페이스를 확인할 수 있음