일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 웹스크래핑
- 분산 시스템
- 추천 시스템
- 웹크롤링
- 알고리즘
- Python
- 코딩테스트
- pytorch
- 파이썬
- 부스트캠프
- 협업 필터링
- wordcloud
- 데이터
- Cosine-similarity
- 딥러닝
- TF-IDF
- SGD
- coursera
- 프로그래머스
- codingtest
- 추천시스템
- 백준
- 코테
- Overfitting
- recommendation system
- 시각화
- Tensor
- 데이터 엔지니어링
- 머신러닝
- selenium
- Today
- Total
개발자식
[스크래핑] Web scraping for news articles (1) 본문
1. 뉴스 검색 결과에서 네이버 뉴스 추려내기
import requests
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime #현재날짜&시간 받아오기
import time
import re
- 앞에서 웹 스크래핑에서 사용했던 from urlib.request import urlopen 것을 -> import requests로 대체한다
- url에 한글이 껴있을 때 오류를 방지하기 위해서
query = '데이터분석'
url = "https://search.naver.com/search.naver?where=news&query=" + query
web = requests.get(url).content
source = BeautifulSoup(web, 'html.parser')
# print(source) # source를 그대로 출력할 경우, 담고 있는 텍스트가 무척 많아서 버벅이게 될 수 있습니다.
- web은 바이트 단위로 컴퓨터 이해 용도로 바로 우리가 사용하지 못한다.
HTTP Request
- GET : 존재하는 자원에 대한 요청
- POST : 새로운 자원을 생성
- PUT : 존재하는 자원에 대한 변경
- DELETE : 존재하는 자원에 대한 삭제
+ POST : 정보를 제출하면서 정보를 달라고 요청한다. ( ex. 블로그, 회원가입)
뉴스들의 제목을 크롤링 한다.
news_subjects = source.find_all('a', {'class' : 'news_tit'}) # ResultSet (리스트와 유사한 형태)
subject_list = []
for subject in news_subjects:
subject_list.append(subject.get_text())
print(subject_list)
결과 :
["세종시, 지방세 빅데이터 체납분석… '맞춤형 징수'키로", '영남이공대, 빅데이터 분석 Tool 특강 열어', "경북도, '경북도 지역화폐 데이터 분석 결과' 내놔", '바이브컴퍼니, 식약처 데이터 융합·분석 플랫폼 구축 사업 수주', '경남 빅데이터센터, 지역 데이터 인재 양성한다', "[단독]본업보다 데이터로 돈 번다... 금융·IT서비스 업계 '사활'", '[주총] 허연수 GS리테일 부회장 "데이터 기반으로 고객 서비스 차별화"', '美·EU 간 데이터 전송 다시 가능해졌다…빅테크 기업 ‘환영’', '[특파원 다이어리]中 수출 데이터로 본 코로나 종식 시점', '데이터로 만드는 대구의 미래']
print(news_subjects[0].attrs)
print(news_subjects[0].attrs["href"])
결과 :
{'href': 'http://www.newsis.com/view/?id=NISX20220327_0001808910&cID=10818&pID=10800',
'class': ['news_tit'],
'target': '_blank',
'onclick': "return goOtherCR(this, 'a=nws*a.tit&r=1&i=88000127_000000000000000011085704&g=003.0011085704&u='+urlencode(this.href));",
'title': "세종시, 지방세 빅데이터 체납분석… '맞춤형 징수'키로"}
'http://www.newsis.com/view/?id=NISX20220327_0001808910&cID=10818&pID=10800'
- attrs는 dict 형태로 반환하기 때문에 key 값으로 접근할 수 있다.
-> 맨 아래의 링크를 타고 들어가면 해당 뉴스 링크에 들어갈 수 있다.
- "class"가 리스트인 이유는 여러 개 들어갈 수 있기 때문이다.
문제점 : 각 뉴스들의 내용들이 공통적인 태그나 무언가가 없다.
해결 : "네이버 뉴스" 메뉴를 이용한다. (네이버 뉴스 표시 되어 있는 뉴스만 꺼낸다)
-> class ="info"
for urls in source.find_all('a', {'class' : "info"}):
print(urls.attrs['href'])
결과 :
http://www.newsis.com
https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=102&oid=003&aid=0011085704
http://www.imaeil.com/
https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=102&oid=088&aid=0000751017
http://www.ilyo.co.kr
https://zdnet.co.kr/
https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=105&oid=092&aid=0002251744
http://www.newsgn.com
http://www.fnnews.com/
https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=014&aid=0004809748
http://news1.kr/
https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=421&aid=0005989895
http://www.heraldbiz.com/
https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=104&oid=016&aid=0001969088
https://www.asiae.co.kr/
https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=104&oid=277&aid=0005064286
http://www.hankyung.com/
https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=102&oid=015&aid=0004678455
-> 문제점 : 언론사 링크도 같이 나온다.
-> 이유 : 언론사 링크가 class: info 같이 사용하고 있기 때문이다.
-> 해결 : 네이버 뉴스는 class: info 하나만 사용한다. 이 특징을 이용한다.
class 속성이 한 개인 것만 출력한다.
for urls in source.find_all("a",{"class":"info"}):
print(urls.attrs["class"])
#print(len(urls.attrs["class"]))
if len(urls.attrs["class"]) !=2:
print(urls.attrs["href"])
결과 :
['https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=102&oid=003&aid=0011085704',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=102&oid=088&aid=0000751017',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=105&oid=092&aid=0002251744',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=421&aid=0005989895',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=014&aid=0004809748',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=104&oid=016&aid=0001969088',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=104&oid=277&aid=0005064286',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=102&oid=015&aid=0004678455']
- 클래스가 info 인 것만 (네이버 뉴스) 뽑아낸다.
- 그러나 이 방법은 아쉽다. 웹 스크래핑은 유통기한이 있기 때문에 추후에 안 돌아갈 가능성이 높다.
해결 :
urls_list = []
for urls in source.find_all('a', {'class' : "info"}):
if urls.attrs["href"].startswith("https://news.naver.com"):
urls_list.append(urls.attrs["href"])
urls_list
- 네이버 뉴스의 링크의 특징을 추출한다. ( https://news.naver.com으로 시작한다.)
- "https://news.naver.com" 으로 시작하는 값만 추출한다.
결과 :
['https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=003&aid=0011083015',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=421&aid=0005989550',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=018&aid=0005174362',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=037&aid=0000030558',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=102&oid=277&aid=0005063437',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=101&oid=421&aid=0005989895',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=102&oid=001&aid=0013069300',
'https://news.naver.com/main/read.naver?mode=LSD&mid=sec&sid1=105&oid=031&aid=0000661550']
2. 단일 뉴스 페이지 분석하기
이전에서 적용했던 방식대로 진행한다.
# # 아래 코드를 실행하면 네이버에서 Bot으로 인식하여 접속을 차단하므로 'ConnectionError'가 발생합니다
web_news = requests.get(urls_list[0]).content
source_news = BeautifulSoup(web_news, 'html.parser')
-> 문제점 :
ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
- 네이버에서 Bot으로 인식하여 접속을 차단하여 ConnectionError 발생한다.
+이러한 ConnectionError는 또 요청이 빠르게 보내질때 발생할 수 있다.
- 해결법 : 코드형 브라우저가 실제 브라우저인척 하며 보낸다.
해결:
# 따라서 아래와 같이 코드를 수정하여 크롬브라우저에서 보내는 요청으로 인식하도록 HTTP Request에 Header 정보를 추가해주면 됩니다.
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
web_news = requests.get(urls_list[0], headers=headers).content
source_news = BeautifulSoup(web_news, 'html.parser')
- http request/response는 head, body로 나누어져 있다.
'Data > Python' 카테고리의 다른 글
[스크래핑] Web scraping for news articles (3) (0) | 2022.03.29 |
---|---|
[스크래핑] Web scraping for news articles (2) (0) | 2022.03.28 |
[Python] 클래스 (Class) (0) | 2022.03.27 |
[크롤링] 웹 크롤링 BeautifulSoup (2) (0) | 2022.03.25 |
[크롤링] 웹 크롤링 BeautifulSoup (1) (0) | 2022.03.25 |