[Python] ์น ํฌ๋กค๋ฌ ๋ง๋ค๊ธฐ with Requests/BeautifulSoup
- -
๐ ์น ํฌ๋กค๋ฌ๋?
์ด๋ ํ ์ ๋ณด๋ฅผ ๋ธ๋ผ์ฐ์ ์์๋ง ๋ณด๋ ๊ฒ๋ฟ ์๋๋ผ ๋ด๊ฐ ์ด์ฉํ๊ธฐ ํธํ ๋ฐฉ์์ผ๋ก ๋ณด๊ดํ๊ฑฐ๋ ์กฐ์ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
Python์ ์ด์ฉํ๋ฉด ๊ฐ๋จํ ์ฝ๋ ๋ช์ค ๋ง์ผ๋ก๋ ์ฝ๊ฒ ์น ์ฌ์ดํธ์์ ์ํ๋ ์ ๋ณด๋ง์ ๊ฐ์ ธ์ ๋ค๋ฃฐ ์ ์๋ค.
๐ ์น์์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
โค Requests๋ฅผ ์ด์ฉํ๊ธฐ
python์๋ requests ๋ผ๋ ์ ๋ช ํ http request๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ค.
โค ์ค์นํ๊ธฐ
pip3 install requests
from rest_framework.views import APIView
from rest_framework.response import Response
from pocket.models import List
from pocket.serializers import ListSerializer
import requests
class ParseAPIView(APIView):
def get(self, request):
queryset = List.objects.all()
serializer = ListSerializer(queryset.first())
# HTTP GET Requests
req = requests.get('https://laagom.tistory.com/')
# HTTP ์์ค ๊ฐ์ ธ์ค๊ธฐ
html = req.text
# HTTP Header ๊ฐ์ ธ์ค๊ธฐ
header = req.headers
# HTTP Status ๊ฐ์ ธ์ค๊ธฐ (200: ์ ์)
status = req.status_code
# HTTP๊ฐ ์ ์์ ์ผ๋ก ๋์๋์ง (True/False)
is_ok = req.ok
return Response(serializer.data)
์ ์ฝ๋์์ ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ ๊ฒ์ HTML ์์ค๋ฅผ ์ด์ฉํ๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ html = req.text๋ฅผ ์ด์ฉํ๋ค.
์์ ๋์จ html, header, status, is_ok๋ฅผ ์ถ๋ ฅํด ๋ณธ ๊ฒฐ๊ณผ ์ ๋๋ก ์์ฒญํด์ ๊ฐ์ ธ์จ ๋ฌธ์์ด์ ํ์ธํ ์ ์์๋ค.
header: { 'Date': 'Mon, 07 Nov 2022 07:46:32 GMT'
, 'Content-Type': 'text/html;charset=UTF-8'
, 'Transfer-Encoding': 'chunked'
, 'Vary': 'Accept-Encoding'
, 'T_USERID': '800cdc655e5524bc59b66df34b1f68145caade80'
, 'Set-Cookie': 'REACTION_GUEST=eb3148932a1f9674bf875d5d26457e0543a9abf5'
, 'X-Content-Type-Options': 'nosniff'
, 'X-XSS-Protection': '1; mode=block'
, 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate'
, 'Pragma': 'no-cache'
, 'Expires': '0'
, 'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains'
, 'Content-Encoding': 'gzip'}
status: 200
is_ok: True
โค BeautifulSoup ์ด์ฉํ๊ธฐ
Requests๋ ์ ๋ง ์ข์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด์ง๋ง, html์ python์์ ์ฌ์ฉํ ์ ์๋ ๊ฐ์ฒด๊ตฌ์กฐ๋ก ์ด์ฉํ๊ธฐ ์ํด์ ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค. ๊ทธ๊ฒ์ด ๋ฐ๋ก BeautifulSoup์ด๋ค. BeautifulSoup์ html์ฝ๋๋ฅผ Python์ด ์ดํดํ๋ ๊ฐ์ฒด ๊ตฌ์กฐ๋ก ๋ณํํ๋ Parsing์ ๋งก๊ณ ์๊ณ , ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด ์ฐ๋ฆฌ๋ ์ ๋๋ก ๋ ์ ๋ณด๋ฅผ ์ถ์ถํด ๋ผ ์ ์๋ค.
pip3 install bs4
BeautifulSoup์ ์ง์ ์ณ์ ์ค์นํ๋ ๊ฒ๋ ๊ฐ๋ฅํ์ง๋ง, bs4๋ผ๋ wrapper๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด ์ค์นํ๋ ๋ฐฉ๋ฒ์ด ๋ ์ฝ๊ณ ์์ ํ๋ค.
โค ์ด์ฉ๋ฐฉ๋ฒ
์์์ ์ด์ฉํ ์์ค์ฝ๋๋ฅผ ์ข ๋ ๋ค๋ฌ์ด ๋ณด์.
import requests
from bs4 import BeautifulSoup
class ParseAPIView(APIView):
def get(slef, request):
queryset = List.objects.all()
serializer = ListSerializer(queryset.first())
# HTTP GET Requests
req = requests.get('https://laagom.tistory.com/')
# HTTP ์์ค ๊ฐ์ ธ์ค๊ธฐ
html = req.text
## BeautifulSoup๋ฅผ ์ด์ฉ
# BeautifulSoup์ผ๋ก html์์ค๋ฅผ python๊ฐ์ฒด๋ก ๋ณํ
soup = BeautifulSoup(html, 'html.parser')
return Response(serializer.data)
์ด soup๊ฐ์ฒด์์ ์ํ๋ ์ ๋ณด๋ฅผ ์ฐพ์๋ผ ์ ์๋ค.
BeautifulSoup์์๋ ์ฌ๋ฌ ๊ฐ์ง ๊ธฐ๋ฅ์ ์ ๊ณตํ๋๋ฐ, ์ฌ๊ธฐ์๋ select๋ฅผ ์ด์ฉํ๋ค. select๋ css selector๋ฅผ ์ด์ฉํด ์กฐ๊ฑด๊ณผ ์ผ์นํ๋ ๋ชจ๋ ๊ฐ์ฒด๋ค์ List๋ก ๋ฐํํด ์ค๋ค. ์์๋ก ๋ด๊ฐ ์์ฑํ๊ณ ์๋ ๊ธฐ์ ๋ธ๋ก๊ทธ์์ a๋งํฌ๋ก ๊ฑธ๋ ค์๋ ๊ฐ์ ๋ชจ๋ ๊ฐ์ ธ์ ๋ณด๋๋ก ํ์
ํ์ฌ ์์ ์ด๋ฏธ์ง๋ ๋ด๊ฐ ์์ฑํ๊ณ ์๋ ๊ธฐ์ ๋ธ๋ก๊ทธ ํํฉํ๋ฉด์ด๋ค. ์ฌ๊ธฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ์ด์ด ๋ธ๋ก๊ทธ์ ๋ชจ๋ ์ ๋ชฉ์ ๊ฐ์ ธ์ ๋ณด๋ ค๊ณ ํ๋ค.
BeautifulSoup์์๋ html์์๋ฟ ์๋๋ผ css๋ ๊ฐ์ ธ์ฌ ์ ์๊ธฐ ๋๋ฌธ์ '.index-item > .article-info > a' ์ ์ํ๋ ๋ชจ๋ ํญ๋ชฉ์ ๊ฐ์ ธ์ค๋ฉด ๋ธ๋ก๊ทธ์ ์ ๋ชฉ์ ๊ฐ์ ธ์ฌ ์ ์์ ๊ฒ์ด๋ค.
from rest_framework.views import APIView
from rest_framework.response import Response
from pocket.models import List
from pocket.serializers import ListSerializer
import requests
from bs4 import BeautifulSoup
class ParseAPIView(APIView):
def get(slef, request):
queryset = List.objects.all()
serializer = ListSerializer(queryset.first())
# HTTP GET Requests
req = requests.get('https://laagom.tistory.com/')
# HTTP ์์ค ๊ฐ์ ธ์ค๊ธฐ
html = req.text
## BeautifulSoup๋ฅผ ์ด์ฉ
# BeautifulSoup์ผ๋ก html์์ค๋ฅผ python๊ฐ์ฒด๋ก ๋ณํ
soup = BeautifulSoup(html, 'html.parser')
my_titles = soup.select(
'.index-item > .article-info > a'
)
print(my_titles)
return Response(serializer.data)
my_titles๋ผ๋ ๋ณ์์ soup๊ฐ์ฒด์ selectํจ์๋ฅผ ์ด์ฉํด css๊ฐ์ฒด์ ์ ๊ทผํด์ ๋ด๊ฐ ์ํ๋ ํ๊ทธ์ ๋ธ๋ก๊ทธ์ ์ ๋ชฉ์ ๊ฐ์ง๊ณ ์๋ดค๋ค.
์์ base shell์์ ์ถ๋ ฅํ ๊ฒฐ๊ณผ๋ my_titles์ ๋ด๊ธด ๋ชฉ๋ก์ ๊ทธ๋๋ก ๋ณด์ฌ์ค ๊ฑฐ๋ผ ๊น๋ํ์ง ์๊ณ ํ๊ทธ์ ์์๊ฐ ์์ฌ ์์ด ๋ณด๊ธฐ ์ด๋ ต๋ค.
# HTTP GET Requests
req = requests.get('https://laagom.tistory.com/')
# HTTP ์์ค ๊ฐ์ ธ์ค๊ธฐ
html = req.text
## BeautifulSoup๋ฅผ ์ด์ฉ
# BeautifulSoup์ผ๋ก html์์ค๋ฅผ python๊ฐ์ฒด๋ก ๋ณํ
soup = BeautifulSoup(html, 'html.parser')
my_titles = soup.select(
'.index-item > .article-info > a'
)
# my_titles๋ list๊ฐ์ฒด
for title in my_titles:
# Tag์์ ํ
์คํธ
print(f'title = {title.text}')
# Tag์ ์์ฑ์ ๊ฐ์ ธ์ค๊ธฐ(ex: href์์ฑ)
print(f'url = {title.get("href")}')
์์ฒ๋ผ ๋ฐ๋ณต๋ฌธ์ ๋๋ ค ์ ๋ชฉ์ text์ url๋ง ๋ฝ์์ ํ์ธํด ๋ณด์.
'LANGUAGES > Python' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Python] ํ์ด์ฌ ์ค๋ฒ๋ผ์ด๋ฉ๊ณผ ์ค๋ฒ๋ก๋ฉ (0) | 2023.05.16 |
---|---|
[Python] format(์ฒ๋จ์ ์ฝค๋ง ์ฝ์ ํ๊ธฐ) (0) | 2023.05.04 |
๋น์ ์ด ์ข์ํ ๋งํ ์ฝํ ์ธ
์์คํ ๊ณต๊ฐ ๊ฐ์ฌํฉ๋๋ค