-
[Python] re 모듈을 통해 정규표현식으로 window.__INITIAL_STATE__ 스크래핑[크롤링]하기programming/python 2022. 7. 15. 16:42
1. 정규 표현식이란?
정규표현식(Regular Expression)은 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어입니다.
re 모듈은 파이썬에서 정규표현식을 지원하는 라이브러리입니다.
2. 정규식에 사용되는 메타 문자
[ ] 문자 클래스를 지정하는데 사용됩니다. ex) [a-v] a부터 v까지의 범위, [acv] acv를 가진 문자 . 줄바꿈 을 제외한 모든 문자와 매치 (점 하나는 글자 하나를 의미한다) * 0회 이상 반복 (없어도 상관 없다) ex) do*g ==> dg(o), dooog(o) + 1회 이상 반복 (무조건 한번 이상 등장해야 한다) ex) do+g ==> dg(x), doooog(o) {m, n} m회 이상 n회 이하 ex) do{2,4}g ==> dog(x), doog(o), dooooog(x) l or 조건식을 의미한다. ^ 1.문자열의 시작 의미, 2. 여집합 ex) '^dog' ==> 시작 부분에서 dog인지, [^5] 5를 제외한 숫자 $ 문자열의 끝을 의미한다. ? 0회 이상 1회 이하 \ 이스케이프, 또는 메타 문자를 일반 문자로 인식하게 한다 ( ) 그룹핑, 추출할 패턴을 지정한다. 3. re 모듈의 메서드
match() 문자열의 시작 부분에서 RE가 일치하는지 판단합니다. search() 이 RE가 일치하는 위치를 찾으면서, 문자열을 훑습니다. findall() RE가 일치하는 모든 부분 문자열을 찾아 리스트로 반환합니다. finditer() RE가 일치하는 모든 부분 문자열을 찾아 이터레이터로 반환합니다. 정규식은 많은 내용이 있어 필요할 때 부분 부분 조금씩 익혀가며 공부하는 것이 좋아 보입니다.
정규식 HOWTO — Python 3.10.5 문서
대소 문자를 구분하지 않는 일치를 수행합니다; 문자 클래스와 리터럴 문자열은 대소 문자를 무시하여 문자와 일치합니다. 예를 들어 [A-Z]는 소문자와도 일치합니다. ASCII 플래그로 ASCII가 아닌
docs.python.org
3. 표현식
#표현식 1 p = re.complie(조건) m = p.메서드(정제할 문자열) #표현식 2 - 간단 data = re.메서드(조건, 정제할 문자열)
4. 실전 : window.__INITIAL_STATE__ script 스크래핑 하기
zum(줌) 사이트의 실시간 검색어를 가져와 보겠습니다.
1) 데이터 위치 찾기
검색을 통해 데이터의 위치를 파악해 script태그 안에 json데이터들이 있는 것을 볼 수 있습니다.
(re 모듈을 사용하고 포스팅을 위해 다시 해보는데 위에 div태그도에 데이터가 있는 것을 확인했습니다. - bs4를 통해서도 가능)
(오히려 정규 표현식을 배운 좋은 기회라 생각하고
헛수고라 쓰겠습니다.)2) 데이터 가져오기
import json inport requests url = "https://zum.com/" html_doc = requests.get(url).text print(html_doc)
가져온 사이트의 html 파일을 text로 가져왔는데요, 너무 많아 터미널 창의 공간이 부족할 정도입니다.
3) re 모듈의 메서드와 조건식 사용하여 원하는 데이터 가져오기
--1-- 원하는 데이터들의 반복 또는 공통점 찾기
json형식이기 때문에 }로 끝나는 것을 볼 수 있고 끝에는 세미 콜론(;)으로 끝나는 것을 볼 수 있습니다.
밑줄 친 부분은 필요 없는 부분이기에 조건식을 쓸 때 고려해주시면 되겠습니다.
--2-- 조건식 작성하기
첫 번째, window.__INITIAL_STATE__= 다음으로 오는 데이터가 필요하다.
두 번째, json의 형식이라 }으로 끝난다.
세 번째, js 표현식은 필요 없다 ==> }}; 이후의 text는 필요하지 않다.
"window.__INITIAL_STATE__=(.*});" #해석 #줄바꿈을 제외한 어떠한 문자뜻하는 문자'.'가 0번 이상(무한대 이하)이며 #마지막 문자가 '}'으로 끝나는 문자열의 끝에는 ';'가 오는 것 #()의 이유는 아래
--3-- 데이터 뽑기
단순히 찾는 것이라면 조건식에서 ()는 필요하지 않을 것입니다. 괄호가 있는 이유는 그룹을 지어 원하는 것만 뽑기 위해서입니다.
#()가 없는 경우 data = re.search("window.__INITIAL_STATE__=.*}};", html_doc) print(data.group(0)) >>> 'window.__INITIAL_STATE__= {"adress" : "asdfkl",,,,,,,,,}};' print(data.group(1)) >>> error #()가 있는 경우 data = re.search("window.__INITIAL_STATE__=(.*}});", html_doc) print(data.group(0)) >>> 'window.__INITIAL_STATE__= {"adress" : "asdfkl",,,,,,,,,}};' print(data.group(1)) >>> '{"adress" : "asdfkl",,,,,,,,,}}'
그룹은 왼쪽에서부터 0번으로 생각하시면 되겠습니다.
data = re.search("window.__INITIAL_STATE__=(.*}});", html_doc) #search의 () 안에 것이 0번 그룹 #(.*}}) 가 1번 그룹 ex = re.search('a(b)c', abc) print(ex.group(0) >>> abc print(ex.group(1)) >>>b
5. json으로 바꿔주기 & 원하는 데이터 뽑기
def zum_data(): url = "https://zum.com/" #url의 text 가져오기 html_doc = requests.get(url).text #(조건식, 문자열) data = re.search("window.__INITIAL_STATE__=(.*}});", html_doc) #조건식에서 설정항 그룹핑 데이터 가져오기, json으로 바꿔주기 #(.*}}) data = json.loads(data.group(1)) #원하는 데이터 찾기 (예측과 노동) data = data["headerStore"]["issueWord"]["items"][:11] li = [] for i in data : li.append(i[0]) data = li return data print(zum_data()) >>>['인하대', '이상한 변호사 우영우', '영탁', '소상공인 손실보전금', '박지현', '노제', '송가인 전국투어', '박은빈', '이준석', '아이오닉6', '세종메디칼'] #22.7.14기준
출처.
how to get contents of script (window.__INITIAL_STATE__) in html using python
how to get contents of script (window.__INITIAL_STATE__) in html using python
I'm crawling data by python, but I have problems. data is mixed byte type and string "https:\u002F\u002Finvest.zum.com\u002Finternal\u002Findex\u002F1" data i got is not changed to json
stackoverflow.com
https://docs.python.org/ko/3/howto/regex.html#matching-characters
정규식 HOWTO — Python 3.10.5 문서
대소 문자를 구분하지 않는 일치를 수행합니다; 문자 클래스와 리터럴 문자열은 대소 문자를 무시하여 문자와 일치합니다. 예를 들어 [A-Z]는 소문자와도 일치합니다. ASCII 플래그로 ASCII가 아닌
docs.python.org
'programming > python' 카테고리의 다른 글
[Flask] 로그인 기능 만들기 ft.JWT,Token,Cookie,hashlib (0) 2022.08.29 [Python]동적 페이지 크롤링(스크래핑) with BeautifulSoup & fake_useragent (0) 2022.07.11 [Python] getattr 내장 메서드, 함수 이름으로 호출하기 (0) 2022.07.05