본문 바로가기
Study/Python

[Python #7] Multiple Connections, Web Scrapping

by YOONAYEON 2021. 12. 14.
Python에서의 다중 연결 처리

 

- 기존 single client와 single server 간의 연결만을 처리했다면, 하나의 server가 많은 client와 연결을 하는 방법이다

- 동시성을 해결하는 방법:

   1) fork (프로세스 복제)

   2) threads (프로세스 내의 여러 개의 동작)

   3) asynchronous I/O (selector 기반)

 

 

from socket import *
import selectors # 파일디스크립터의 처리 이벤트를 모니터링 해주는 모듈

sel = selectors.DefalutSelector() #selector생성
s = socket(AF_INET, SOCK_STREAM) #소켓 생성
s.bind((host, port))
s.listen()
s.setblocking(False)	#소켓을 non-blocking모드로 변경
# selector에 관찰할 소켓등록(소켓, 기다리는 이벤트명)
sel.register(s, selectors.EVENT_READ, data=None) # Read요청이 오면 나를 깨워달라

while True:
	events = sel.select(timeout=None) # 등록된 소켓 중 처리해야할 event가 있는 소켓검사 (timeout: 기다릴 시간설정)
    for key, mask in events:	# key: 어떠한 fd인지, mask: 어떠한 이벤트발생인지
    	if key.data is None: # s소켓에 처리해야할 이벤트가 있는경우
        	accpet_wrapper(key.fileobj)	#연결요청 처리, key.fileobj는 client연결을 나타내는 소켓객체
        else:
        	service_connection(key, mask)	#일반적인 클라이언트와의 요청처리

 

def accpet_wrapper(sock):
	conn, addr = sock.accept() #연결요청 처리
    print('from', addr)
    
    conn.setblocking(False) # 클라이언트와의 연결도 non-blocking모드로 셋팅
    data = types.SimpleNamespace(addr=addr, inb=b'', outb=b' ') #data생성
    events = selectors.EVENT_READ | selectors.EVENT_WRITE		#관찰할 event는 READ,WRITE
    sel.register(conn, events, data=data)	#selector에 등록

 

def service_connection(key, mask):	# key: fd, mask: 어떠한 이벤트인지
	sock = key.fileobj	#소켓 가져오기
    data = key.data		#데이터 가져오기
    if mask & selectors.EVENT_READ:		#읽는 경우
    	recv_data = sock.recv(1024)		#소켓으로부터 읽기
        if recv_data:					#데이터가 null이 아니면
        	data.outb += recv_data		
        else:
        	sel.unregister(sock)		#selecotr에서 연결되어있는 소켓 제거
            sock.close()				#소켓 닫기
    if mask & selecotrs.EVENT_WRITE:	#쓰는 경우
    	if data.outb:
        	sent = sock.send(data.outb)	#소켓으로 보내기
            data.outb = data.outb[sent:]

 

 

Python에서의 HTTP 요청

 

- socket 이용

 

import socket

mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)	#소켓 생성
mysock.connect(('data.pr4e.org', 80))	#80번 포트의 웹서버 접근
cmd = 'GET http://data.pr4e.org/romeo.txt HTTP/1.0\n\n'.encode()
mysock.send(cmd)	#소켓을 통해 요청

while True:
	data = mysock.recv(512)	#서버에서 보내주는 웹페이지 받기
    if (len(data) < 1):		#더이상 읽어올 데이터가 없으면
    	break
    print(data.decode())
    
mysock.close()

 

 

- urllib 이용

: HTTP는 굉장히 많이 쓰이므로 소켓을 다루고 웹페이지를 불러오는 라이브러리가 있음

 

# 웹페이지에서 단어의 출현 빈도 계산하기
import urllib.request, urllib.parse, urllib.error

fhand = urllib.request.urlopen('http://data.pr4e.org/romeo.txt') #해당url을 오픈한후 읽어와 디스크립터 반환
for line in fhand:		# 원격에 있는 txt파일을 줄단위로 처리
	words = line.decode().split()
    for w in words:
    	counts[w] = counts.get(w, 0) + 1
print(counts)

 

 

웹 스크래핑

 

- 프로그램이나 스크립트가 브라우저처럼 행동하며, 페이지를 살펴보고 정보를 추출,조사하는 것을 말함

- 검색엔진은 웹페이지를 스크래핑하는 것. (크롤링이라고도 부름)

- 스크래핑하는 이유?

   소셜데이터를 가져오기, 외부로 내보내는 기능이 없는 시스템에서 데이터 가져오기

   사이트를 모니터링하며 새로운 정보 감지, 검색엔진의 db를 구축하기 위해

 

 

BeautifulSoup

 

- urllib + html parsing

- 설치 명령어: pip install beautifulsoup4

 

import urllib.request, urllib.parse, urllib.error, requests	# 웹페이지 열기, 가져오기
from bs4 import BeautifulSoup	# HTML태그 파싱

url = input('Enter: ')
headers = {'user-agent': 'Mozilla/5.0'}	# 사이트 정책
page = requests.get(url, headers = headers) # 페이지요청에 대한 정보
soup = BeautifulSoup(page.content, 'html.parser', from_encoding='utf-8')  #파싱결과 리턴

tags = soup('a')
for tag in tags:					# <a>태그 보면서
	 print(tag.get('href', None)) 	# <a href="">의 값 꺼내기

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

[Python #8] Database  (0) 2021.12.14
[Python #6] Network  (0) 2021.11.24
[Python #5] Class, Module, Package  (0) 2021.10.31
[Python #5] Dictionary, Set, Collection  (0) 2021.10.10
[Python #4] File  (0) 2021.10.07