쫑쫑JJONG
끄적끄적 오후5시37분
쫑쫑JJONG
전체 방문자
오늘
어제
  • 분류 전체보기 (198)
    • Paper Reading (5)
    • Math (5)
    • Data Science (13)
      • SQL (12)
      • Data Analyst (1)
    • AI Track (32)
      • CV (21)
      • CV Remind (2)
      • NLP (1)
      • AI Basic (8)
    • Python (1)
      • Basic (8)
      • Application (5)
    • Robotics (31)
      • ROS (15)
      • Collabot_proj (16)
    • NaverBoost Camp 4기 (45)
      • 부스트일지 (13)
      • [P stage] Image Classificat.. (4)
      • [P stage] Object Detection (12)
      • [P stage] Semantic Segmenta.. (6)
      • [P stage] Final Project (5)
      • CV (1)
      • DL BASIC (4)
    • Excel (1)
    • Git (8)
      • Git (8)
    • Network (3)
      • 통신 (3)
    • 코테준비 (14)
      • Programmers (11)
      • 기타 (3)
    • 환경설정 (19)
    • etc (7)
      • 활동 (2)
      • TIP (3)
      • 잡동사니 (2)
    • 금융관련 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • 포트폴리오

인기 글

태그

  • Data Scraping
  • CV
  • 환경설정
  • GIT
  • Monte Carlo Sampling
  • segmentation
  • 논문분석
  • 이고잉
  • diffusion
  • error
  • robotics
  • Arduino
  • collabot
  • mmdetection
  • SQL
  • NLP
  • python
  • transformer
  • N
  • ros
  • Confusion Matrix

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
쫑쫑JJONG

끄적끄적 오후5시37분

[Scraping] HTML, XPath, Requests,정규식 찍먹해보기 (+User-agent)
Python/Application

[Scraping] HTML, XPath, Requests,정규식 찍먹해보기 (+User-agent)

2023. 1. 19. 01:11
728x90

다음 강의를 정리하여 작성하였습니다

https://www.youtube.com/watch?v=yQ20jZwDjTE&list=LL&index=3&t=1526s 

 

웹 스크래핑 -> 웹 페이지에서 내가 원하는 정보를 가져 오는 것

웹 크롤링 -> 웹페이지에서 링크를 따라가며 모든 내용을 가져오는 것

 

HTML

Hyper Text Markup Language

즉 웹페이지 만드는 언어이다

 

 

VSC에서 이걸 열고 싶으면

위 extension을 다운받으면 된다

 

 

HTML은 아래와 같이 코드를 작성한다

 

보통 다음과 같이

<html>
    <head>
    </head>
    <body>
    </body>
</html>

이것을 기본 구조로 가진다

 

이를 응용해보면

<html>
    <head>
        <title>승종 홈페이지</title>>
    </head>
    <body>
        <h1> Hello World</h1>
        <input type="text" value="아이디를 입력하세요">
        <input type="password" value="비밀번호를 입력하세요">
        <input type="button" value="로그인">
    </body>
</html>

먼저 꺽쇠로 시작을 하고 /로 닫으므로써 element로 구성한다

 

바로닫고 싶으면 <html/> 이렇게도 쓴다

 

head : 홈페이지의 제목, 선행작업

body : 웹페이지의 본문

h1 : 글자가 크게 나옴

 

element들의 세부 속성을 attribute를 통해 지정을 하고

위에서는 type과 value를 사용 하였다

 

이를 출력해보면

다음과 같이 출력이 되고 만약 한글이 깨진다면

<html>
    <head>
    	<meta charset="utf-8">
        <title>승종 홈페이지</title>>
    </head>
    <body>
        <h1> Hello World</h1>
        <input type="text" value="아이디를 입력하세요">
        <input type="password" value="비밀번호를 입력하세요">
        <input type="button" value="로그인">
    </body>
</html>

다음과 같이 meta를 이용하여서 선행작업을 수행해주면 된다

 

그러면 링크는 어떻게 걸까???

 

<html>
    <head>
        <title>승종 홈페이지</title>>
    </head>
    <body>
        <h1> Hello World</h1>
        <input type="text" value="아이디를 입력하세요">
        <input type="password">
        <input type="button" value="로그인">
        <a href="http://google.com"> 구글로 이동하기 </a>>
    </body>
</html>

다음과 같이 a href를 이용하면 된다

 

다음과 같이 하이퍼링크가 생긴다

 

추가적인 공부는

https://www.w3schools.com/

 

W3Schools Free Online Web Tutorials

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

여기에서 추가 공부를 하면 된다

 

XPath

다음과 같은 예시를 보자

<학교 이름 = "고등학교">
	<학년 value= "1학년">
        <반 value="1반">
            <학생 value="1번" 학번 = "1-1-1">이지은</학생>
            <학생 value="2번" 학번 = "1-1-2">가나다</학생>
            <학생 value="3번" 학번 = "1-1-3">라마바</학생>
            <학생 value="4번" 학번 = "1-1-4">이지은</학생>
        </반>
        <반 value="2반"/>
        <반 value="3반"/>
        <반 value="4반"/>
    </학년>
    <학년 value= "2학년">
    <학년 value= "3학년">
</학교>

나는 1학년 1반 4번 이지은을 부르고 싶은데 1번이랑 이름이 겹쳐서 혼동이 올 수 도 있다

 

즉, 어떤 element를 지칭하는지를 확실하게 하기 위해 XPath를 사용

 

ex)

/학교/학년/반/학생[2]

[2]: 두번째 element

 

이렇게 하면 복잡해지면 너무 깊어지기 때문에 위에서 학번을 지정해줌

 

ex)

//*[@학번 = '1-1-3']

이렇게 줄일 수 있다

학번이 1-1-3인 걸 모든 문서에서 찾아주세요 라는 뜻

 

/ : 하위 디렉토리

// : 모든 하위 디렉토리

* : 이름 상관 없이

 

즉, 다음과 같이 2가지 표현이 있다 

/학교/학년/반/학생[2]

//*[@학번 = '1-1-3']

 

 

ex)

다음과 같이 네이버의 로그인 버튼 부분을 가져와 보자

다음과 같이

full XPath로 가져오면

/html/body/div[2]/div[3]/div[3]/div/div[2]

이고

XPath 로 가져오면

//*[@id="account"]

이다

 

Chrome

원하는 element에 마우스 올리고 우클릭하고 검사를 누르거나

 

단축키 f12

 

저 버튼을 누르고

화면에 원하는 부분을 클릭하면 해당 element로 호출이 자동으로 된다

 

 

 

Requests 라이브러리

웹 스크래핑을 위해 html 문서 정보를 가져와야하는데 이를 해줌

 

pip install requests

 

다음 코드를 통해 설명

import requests
res = requests.get("http://naver.com") #url에 대한 정보를 받아와 res에 저장

#서버 응답이 정상적인지 확인하는 방법
print("응답코드 : ", res.status_code) #200이면 정상
#ex) 403 -> 접근권한이 없다

#응용 -> 아래의 세개가 같은 기능이다

if res.status_code == 200:
    print("서버 응답이 정상적이다")
else:
    print("문제가 생겼습니다  [에러코드 : ",res.status_code, "]")


if res.status_code == requests.codes.ok:
    print("서버 응답이 정상적이다")
else:
    print("문제가 생겼습니다  [에러코드 : ",res.status_code, "]")


res.raise_for_status() #문제 없을땐 pass, 문제 있을땐 error
print("웹 스크래핑을 진행합니다")

 

위에서 가져온 res에 문자들을 보고 싶으면

print(res.text)

이를 응용해보면

 

import requests
res = requests.get("http://google.com") #url에 대한 정보를 받아와 res에 저장

#서버 응답이 정상적인지 확인
res.raise_for_status() #문제 없을땐 pass, 문제 있을땐 error
print("웹 스크래핑을 진행합니다")
print("웹 페이지 문자 개수 : ", len(res.text))

with open("mygoogle.html", "w", encoding= "utf-8") as f:
    f.write(res.text)

를 실행했더니 다음과 같이

AttributeError: partially initialized module 'requests' has no attribute 'get' (most likely due to a circular import)

가 떴다

 

이는 파일명과 모듈명이 동일 (requests.py) 해서 발생한 error 이므로 파일명을 바꿔주도록 한다

 

이제 mygoogle.html을 열어보면 

다음과 같이 글씨만 전부 가져온 것을 볼 수 있다

 

정규식

정규식 : Regular Expression 

줄여서 re, regex, regexp 라고 많이 쓴다

 

의미는 정해진 형식이라고 해석하면 된다

 

사용법

import re

 

다음과 같은 구조를 가지는 단어를 찾는다 가정을 하자

c a _ e 

 

다음과 같이 코드를 짤 수 있다

import re

#어떤 정규식을 컴파일 할지를 정함
p = re.compile("ca.e")

m = p.match("case")
#p.match("비교할 값")

print(m.group()) #만족하는 문자들을 출력, 매치되지 않으면 error가 발생
  •  . : 하나의 문자 cafe 가능 caffe 등은 불가
  • ^ : 문자열의 시작 ex) ^de : desk, destination 가능 face : 불가
  • $ : 문자열의 끝 ex) $ie  -> compile , pie .....

이를 이용하여서 매칭 되었을 때만 처리하는 코드

import re

#어떤 정규식을 컴파일 할지를 정함
p = re.compile("ca.e")

m = p.match("case")

if m:
    print(m.group) #만족하는 문자들을 출력, 매치되지 않으면 error가 발생
else:
    print("매칭되지 않음")

이렇게 해서 error를 발생하지 않고 할 수 있다

 

다음과 같이 응용을 할 수 있다

 

주의점

import re

#어떤 정규식을 컴파일 할지를 정함
p = re.compile("ca.e") 

def print_match(m):
    if m:
        print(m.group())
    else:
        print("매칭되지 않음")

m = p.match("careless")
print_match(m)

이거는 매치가 된다 (뒤에는 뭐가 있던지 상관없음 -> 앞에 부터 care면 ok)

 

아래는 매칭되지 않는다고 나온다

import re

#어떤 정규식을 컴파일 할지를 정함
p = re.compile("ca.e") 

def print_match(m):
    if m:
        print(m.group())
    else:
        print("매칭되지 않음")

m = p.match("good care")
print_match(m)

 

그러면 위와 같이 주어진 문자열 중에 일치하는게 있는지 확인하는 방법은 무엇일까?

 

Search()를 이용

 

import re

#어떤 정규식을 컴파일 할지를 정함
p = re.compile("ca.e") 

def print_match(m):
    if m:
        print(m.group())
    else:
        print("매칭되지 않음")

m = p.search("good care")
print_match(m)

이러면 주어진 문자열 중에 일치하는게 있는지를 확인하는 것이다

 

그런데 이렇게 하면

print(m.group())에서

>> care 라고 출력이 된다. 이걸 good care로 출력을 하려면 어떻게 해야할까?

 

p.search(), p.match() 의 결과 값을 받은 m 은 다양한 기능들이 있는데

 

  • m.group() : 일치하는 문자열 반환
  • m.string : 입력받은 문자열 -> 이건 함수가 아님
  • m.start() : 일치하는 문자열의 시작 index
  • m.end() : 일치하는 문자열의 끝 index
  • m.span() : 일치하는 문자열의 시작과 끝 index를 함께 출력

를 이용할 수 있다

 

밑에 코드에서 자세히 알아보자

import re

#어떤 정규식을 컴파일 할지를 정함
p = re.compile("ca.e") 

def print_match(m):
    if m:
        print("m.group() : ", m.group()) # : 일치하는 문자열 반환
        print("m.string : ", m.string) # : 입력받은 문자열 -> 이건 함수가 아님
        print("m.start() : ", m.start()) # : 일치하는 문자열의 시작 index
        print("m.end() : ", m.end())# : 일치하는 문자열의 끝 index
        print("m.span() : ",m.span()) #: 일치하는 문자열의 시작과 끝 index를 함께 출력
    else:
        print("매칭되지 않음")

m = p.search("good care")
print_match(m)

를 실행하면 다음과 같은 결과를 얻을 수 있다

 

그러면 p.match 와 search 말고는 뭐가 있을까??

 

findall()

-> 일치하는 모든 것을 리스트 형태로 반환

import re

#어떤 정규식을 컴파일 할지를 정함
p = re.compile("ca.e") 

lst = p.findall("good care cafe")
print(lst)

를 실행시키면

다음과 같은 list를 확인할 수 있다

 

정리

1.  p = re.compile("원하는 형태") 을 통해 형태를 받아 온다
2.  다양한 함수를 통해 확인을 한다
m = p.match("비교할 문자열 ") : 주어진 문자열의 처음부터 일치하는지 확인
m = p.search("비교할 문자열 ") : 주어진 문자열 중에 일치하는게 있는지 확인
lst = p.findall("비교할 문자열 ") : 일치하는 모든 것을 리스트 형태로 반환

※원하는 형태
.  (ca.e) : 하나의 문자를 의미 > care, cafe, case (O) | caffe (X)
^ (^de) : 문자열의 시작 > desk, destination (O) | fade (X)
$ (se$) : 문자열의 끝 > case, base (O) | face (X)

 

추가적인 공부는 마찬가지로

https://www.w3schools.com/python/python_regex.asp

 

Python RegEx

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

여기나 re 공식 문서 사이트

https://docs.python.org/3/library/re.html

 

re — Regular expression operations

Source code: Lib/re/ This module provides regular expression matching operations similar to those found in Perl. Both patterns and strings to be searched can be Unicode strings ( str) as well as 8-...

docs.python.org

를 통해서 공부가 가능하다

 

User Agent

만약 네이버에서 권한을 주지 않으면 다음의 코드를 실행시켜보면 403 error 가 난다

import requests
res = requests.get("http://naver.com") #url에 대한 정보를 받아와 res에 저장
res.raise_for_status() #문제 없을땐 pass, 문제 있을땐 error
with open("mycrowling.html", "w", encoding= "utf8") as f :
    f.write(res.text)

예시

그러면 어떻게 해결을 할까???

 

다음의 사이트를 통해 나의 User Agent 정보를 확인하자

https://www.whatismybrowser.com/detect/what-is-my-user-agent/

 

What is my user agent?

Every request your web browser makes includes your User Agent; find out what your browser is sending and what this identifies your system as.

www.whatismybrowser.com

를 보면

저 빨강색 박스 부분을 확인할 수 있다 (굳이 모자이크 필요 없는데// )

그러면 다시 돌아와서 다음의 User Agent 정보를 넘겨주자

 

headers 라는 변수를 만들어서 requests.get에 parameter로 넘겨주자

import requests
url  = "http://naver.com"
headers = {"User-Agent" : "빨강색 박스 부분 복붙"}
res = requests.get(url, headers = headers)
res.raise_for_status() #문제 없을땐 pass, 문제 있을땐 error
with open("mycrowling.html", "w", encoding= "utf8") as f :
    f.write(res.text)

쉽게 말해서 그냥 불법 프로그램이 아닌 사람이라는 것을 알려주는 것이라 생각하면 될 것 같다

(즉, 우리가 크롬등을 통해서 접근한 것과 동일한 정보를 얻을 수 있다)

728x90
저작자표시 비영리 변경금지 (새창열림)

'Python > Application' 카테고리의 다른 글

[Python] Streamlit 활용 전 정리  (0) 2024.06.05
[Data Scraping] Error : Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same  (0) 2023.02.10
[Data Scraping] 구글에서 고화질 이미지 스크래핑(크롤링) - selenium  (0) 2023.01.27
[Scraping] Web Crowling 이라기 보단 Scraping (beautifulsoup4)  (0) 2023.01.24
    'Python/Application' 카테고리의 다른 글
    • [Python] Streamlit 활용 전 정리
    • [Data Scraping] Error : Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same
    • [Data Scraping] 구글에서 고화질 이미지 스크래핑(크롤링) - selenium
    • [Scraping] Web Crowling 이라기 보단 Scraping (beautifulsoup4)
    쫑쫑JJONG
    쫑쫑JJONG
    connect : tmdwhd619@naver.com

    티스토리툴바