멋사 ai 스쿨 TIL - (14) 서울정보소통광장 웹스크래핑

eve·2022년 10월 4일
0

likeLion

목록 보기
12/45

1. ANACONDA를 사용하는 이유

  • python이 둘러싼 라이브러리들은 내부에 C나 java가 들어가 있는 경우도 있음
  • 해당 언어들을 실행할 환경 설정이 되어 있지 않은 경우 에러가 발생함
  • 버전 호환성 맞춰주기도 쉽지 않음
  • 기타 언어에 의존성 높아서 활용 불가한 패키지 배제

2. http method

  • 백엔드로 갈 것이라면 익혀둬야 함
  • Query String Parameter에서 callback값, gid값을 확인할 것

3. html.parser
beautifulSoup는 웹데이터 수집기라기보다는 parser에 가깝다. html/xml 파일을 읽기 편하게 가공한다.
아래와 같이 html/xml 중 파싱할 대상을 정해줄 수 있다.

bs(response.text, 'html.parser')

4. 데이터베이스권
예시: 네이버 증권 게시판에 글을 쓰면, 데이터베이스권은 네이버에 있으며 저작권은 글쓴이에게 있다.

5.웹스크래핑 시나리오
(1) url 가져오기 - requests 활용
(2) beautifulsoup를 활용해 파싱
(3) 반복문으로 페이지 범주 설정
(4) 데이터프레임으로 반환

6.인코딩

pd.read_html(base_url, encoding = "cp949")

또는, encoding = "utf-8"을 적어주면 됨.

7. a tag parsing

html = bs(response.text)
html.select("td.data-title.aLeft > a")

링크 '<a href =~' 에 해당하는 라인에서 css selector를 카피해와서 넣어줄 수 있다 (child 언급된 부분은 삭제 요망)

찐스크래핑

  def get_one_page(page_no):
    120 주요질문의 특정 페이지 목록을 수집
       a_link_no = []
    for a_tag in a_list:
        a_link_no.append(a_tag["href"].split("/")[-1])
    table[0]["내용번호"] = a_link_no

7~8 번 코드를 위와 같이 작성하였는데
차이점을 논하자면 a_link_no라는 빈 변수를 선언하고
내용물을 꺼내서 변수 밖에서 설명해주고 다시 넣어준 것이 위의 코드이다.
아래의 코드는 table의 내용번호 컬럼을 생성하면서 a tag와의 관계를 바로 컬럼에 설정해주었다.

    #1) page_no 마다 url이 변경되도록 f-string을 사용
    base_url = f"https://opengov.seoul.go.kr/civilappeal/list?items_per_page=50&page={page_no}"
    #2) requests를 사용해서 요청을 보내고 응답 받기
    response = requests.get(base_url)
    #3) pd.read_html을 사용해서 table tag로 게시물을 읽어오기
    #4) 3번 결과에서 0번 인덱스를 가져와 데이터프레임으로 목록의 내용 만들기
    table = pd.read_html(response.text)[0]
    #5) html tag를 parsing할 수 있도록 bs 형태로 만들기
    pd.read_html(base_url, encoding = "utf-8")
    html = bs(reponse.text)
    #6) 목록 안에 있는 a_tag를 찾기
    a_list = html.select("td.data-title.aLeft > a")
    #7) a tag 안에서 string을 분리해서 내용번호만 리스트 형태로 만들기
    #8) 4)의 결과에 "내용번호"라는 컬럼을 만들고 a tag의 리스트를 추가
    table["내용번호"] = [a_tag["href"].split("/")[-1] for a_tag in a_list]

    return table

에러메세지 출력 포함 ver.

   #1) page_no 마다 url이 변경되도록 f-string을 사용
    base_url = f"https://opengov.seoul.go.kr/civilappeal/list?items_per_page=50&page={page_no}"
    #2) requests를 사용해서 요청을 보내고 응답 받기
    response = requests.get(base_url)
    #3) pd.read_html을 사용해서 table tag로 게시물을 읽어오기
    #4) 3번 결과에서 0번 인덱스를 가져와 데이터프레임으로 목록의 내용 만들기
    table = pd.read_html(response.text)[0]
    if table.shape[0] == 0:
        return f"{page_no} 페이지를 찾을 수 없습니다."
    #5) html tag를 parsing할 수 있도록 bs 형태로 만들기
    try:
        html = bs(response.text)
    #6) 목록 안에 있는 a_tag를 찾기
        a_list = html.select("td.data-title.aLeft > a")
    #7) a tag 안에서 string을 분리해서 내용번호만 리스트 형태로 만들기
    #8) 4)의 결과에 "내용번호"라는 컬럼을 만들고 a tag의 리스트를 추가
        table["내용번호"] = [a_tag["href"].split("/")[-1] for a_tag in a_list]
    except:
        # 중간에 오류가 발생해도 계속 코드를 진행해야 하는 경우, 에러메세지를 출력하게 해준다
        return f"{page_no}페이지를 찾을 수 없습니다."
    return table

조건을 걸어준 try문except문을 기억하자 - 예외조건을 제외하고는 모두 try에 넣어준다는 의미

여러 페이지 수집하기 - 바닥날 때까지 반복문

# time.sleep을 통해 일정 간격 쉬었다가 가져옵니다.
# 게시물이 없으면 멈춥니다.
page_no = 1
table_list = []

while True:
   df_temp = get_one_page(page_no)
   if type(df_temp) == str:
       print("수집이 완료되었습니다.")
       break
   print(page_no, end=",")
   table_list.append(df_temp)
   page_no +=1
   time.sleep(0.01)

여기서는 df_temptime.sleep에 유의할 것!

특정 페이지 읽어오기

# 내용 페이지의 주소를 url 변수에 담아줍니다.
# 웹페이지의 결과를 받아옵니다.
# BeautifulSoup을 통해 lxml로 파싱해 올 수 있도록 합니다.
# html 태그에서 "div.line-all"의 0번째 값을 선택(select)하여 text를 확인합니다. 

url = "https://opengov.seoul.go.kr/civilappeal/view/?nid=23194045"
print(url)
response =requests.get(url)
html = bs(response.text)
# content
contetnt = html.select("div.view-content.view-content-article > div > div.line-all")[0].get_text()

행과 열을 바꿔주기

table[[0,1]].set_index(0).T

t는 행과 열을 바꿔주는 기능을 한다. 전치 행렬을 의미 - transform

table[[a,3]].set_index(a).T

a의 숫자를 맞춰줘야 결과가 나온다. a는 어떤 컬럼을 인덱스로 만들 것인지 지정해주는 값이다.

두 개의 인덱스 합체

pd.concat([tb01, tb02], axis=1)

표1과 표2의 값을 합침 - 기준은 axis

  1. 인덱스 확인하기
tb01.columns, tb02.columns
  1. map과 apply는 반복문을 사용하지 않고 함수를 일괄적으로 적용시키기 위함임
profile
유저가 왜 그랬을까

0개의 댓글