[오토핫키] Winhttp 활용하여 뉴스 크롤링하기

2024. 10. 17. 09:16오토핫키 오픈 스크립트

 

 

 

Winhttp 활용하여 뉴스 제목 및 기사를 크롤링 하는 스크립트입니다.

 

공부용으로 살펴보시면 좋습니다.

 

; WinHTTP 객체 생성
wh := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")

; 첫 번째 사이트에서 HTML 소스 가져오기
url1 := "https://www.hankyung.com/economy/0408"
wh.Open("GET", url1)
wh.Send()
htmlSource1 := wh.ResponseText()

; 불필요한 공백 및 줄바꿈 제거
cleanHtml1 := RegExReplace(htmlSource1, "\s+", " ")

; 첫 번째 사이트의 기사 제목 및 링크 추출
articlePattern1 := "<a[^>]*href=""(https://www\.hankyung\.com/article/[^""]*)""[^>]*>(.*?)</a>"
titles1 := []
links1 := []
pos1 := 1

while pos1 := RegExMatch(cleanHtml1, articlePattern1, match1, pos1)
{
    titleText1 := RegExReplace(match12, "<img[^>]*>", "")
    if (Trim(titleText1) != "")
    {
        ; HTML 엔티티를 실제 문자로 변환
        titleText1 := RegExReplace(titleText1, "&quot;", """")
        titleText1 := RegExReplace(titleText1, "&amp;", "&")
        titleText1 := RegExReplace(titleText1, "&lsquo;", "‘")
        titleText1 := RegExReplace(titleText1, "&rsquo;", "’")
        titleText1 := RegExReplace(titleText1, "&ldquo;", "“")
        titleText1 := RegExReplace(titleText1, "&rdquo;", "”")
        titleText1 := RegExReplace(titleText1, "&nbsp;", " ")

        links1.Push(match11)
        titles1.Push(Trim(titleText1))
    }
    pos1 += StrLen(match1)
}

; 두 번째 사이트에서 HTML 소스 가져오기
url2 := "https://www.ytn.co.kr/news/list.php?mcd=0102"
wh.Open("GET", url2)
wh.Send()
htmlSource2 := wh.ResponseText()

; 불필요한 공백 및 줄바꿈 제거
cleanHtml2 := RegExReplace(htmlSource2, "\s+", " ")

; 두 번째 사이트의 기사 제목 및 링크 추출
articlePattern2 := "<a[^>]*href=""(https://www\.ytn\.co\.kr/_ln/0102_[^""]*)""[^>]*>([^<]*)</a>"
titles2 := []
links2 := []
pos2 := 1

while pos2 := RegExMatch(cleanHtml2, articlePattern2, match2, pos2)
{
    titleText2 := Trim(match22)
    if (titleText2 != "")
    {
        ; HTML 엔티티를 실제 문자로 변환
        titleText2 := RegExReplace(titleText2, "&quot;", """")
        titleText2 := RegExReplace(titleText2, "&amp;", "&")
        titleText2 := RegExReplace(titleText2, "&lsquo;", "‘")
        titleText2 := RegExReplace(titleText2, "&rsquo;", "’")
        titleText2 := RegExReplace(titleText2, "&ldquo;", "“")
        titleText2 := RegExReplace(titleText2, "&rdquo;", "”")
        titleText2 := RegExReplace(titleText2, "&nbsp;", " ")

        links2.Push(match21)
        titles2.Push(titleText2)
    }
    pos2 += StrLen(match2)
}

; 첫 번째 리스트뷰 추가
Gui, Add, ListView, r10 w600 vListView1 gListViewDoubleClick1, 한국경제
LV_ModifyCol(1, "AutoHdr")
for index, title in titles1
{
    LV_Add("", title)
}

; 두 번째 리스트뷰 추가
Gui, Add, ListView, r10 w600 vListView2 gListViewDoubleClick2, YTN 뉴스
LV_ModifyCol(1, "AutoHdr")
for index, title in titles2
{
    LV_Add("", title)
}

Gui, Show
Return

; 첫 번째 리스트뷰 기사 본문 추출 함수
ExtractArticleBody1(Source) {
    ; </figure> 태그 이후부터 .com 이전까지의 텍스트를 추출
    RegExMatch(Source, "</figure>(.*?)\.com", match)
    ArticleBody := match1

    ; <br /> 태그를 줄바꿈으로 대체
    ArticleBody := RegExReplace(ArticleBody, "<br\s*/?>", "`n")

    ; HTML 엔티티를 실제 문자로 변환
    ArticleBody := RegExReplace(ArticleBody, "&lsquo;", "‘")
    ArticleBody := RegExReplace(ArticleBody, "&rsquo;", "’")
    ArticleBody := RegExReplace(ArticleBody, "&ldquo;", "“")
    ArticleBody := RegExReplace(ArticleBody, "&rdquo;", "”")
    ArticleBody := RegExReplace(ArticleBody, "&nbsp;", " ") 
    ArticleBody := RegExReplace(ArticleBody, "&quot;", """") 
    ArticleBody := RegExReplace(ArticleBody, "&amp;", "&") 
    ArticleBody := RegExReplace(ArticleBody, "&#39;", "'") 

    ; 앞뒤 공백 제거
    ArticleBody := Trim(ArticleBody)

    return ArticleBody
}

; 두 번째 리스트뷰 기사 본문 추출 함수
ExtractArticleBody2(Source) {
    ; <span style로 시작하고 </span>으로 끝나는 텍스트 추출 (s 플래그는 정규 표현식 패턴에 포함)
    RegExMatch(Source, "(?s)<span style.*?>(.*?)</span>", match)
    ArticleBody := match1

    ; <br /> 태그를 줄바꿈으로 대체
    ArticleBody := RegExReplace(ArticleBody, "<br\s*/?>", "`n")

    ; HTML 엔티티를 실제 문자로 변환
    ArticleBody := RegExReplace(ArticleBody, "&lsquo;", "‘")
    ArticleBody := RegExReplace(ArticleBody, "&rsquo;", "’")
    ArticleBody := RegExReplace(ArticleBody, "&ldquo;", "“")
    ArticleBody := RegExReplace(ArticleBody, "&rdquo;", "”")
    ArticleBody := RegExReplace(ArticleBody, "&nbsp;", " ") 
    ArticleBody := RegExReplace(ArticleBody, "&quot;", """") 
    ArticleBody := RegExReplace(ArticleBody, "&amp;", "&") 
    ArticleBody := RegExReplace(ArticleBody, "&#39;", "'") 

    ; 앞뒤 공백 제거
    ArticleBody := Trim(ArticleBody)

    return ArticleBody
}


; 첫 번째 리스트뷰 더블클릭 이벤트 처리
ListViewDoubleClick1:
if (A_GuiEvent = "DoubleClick")
{
    LV_GetText(selectedTitle1, A_EventInfo)
    selectedLink1 := links1[A_EventInfo]
    
    ; 기사 본문 가져오기
    wh.Open("GET", selectedLink1)
    wh.Send()
    articleSource1 := wh.ResponseText()
    articleBody1 := ExtractArticleBody1(articleSource1)

    ; 기사 본문을 보여주는 새 GUI 창 생성
    Gui, 2:Destroy  ; 이전 GUI가 있으면 파괴
    Gui, 2:Add, Text,, % "기사 링크: " selectedLink1
    Gui, 2:Add, Edit, r20 w600, % articleBody1
    Gui, 2:Add, Button, gOpenLink1, 링크 열기
    Gui, 2:Show,, 기사 본문
}
Return

OpenLink1:
{
    ; 클릭 시 기본 웹 브라우저에서 링크 열기
    Run, %selectedLink1%

    ; 링크 열기 버튼 클릭 후 GUI 창 파괴
    Gui, 2:Destroy
}
Return

; 두 번째 리스트뷰 더블클릭 이벤트 처리
ListViewDoubleClick2:
if (A_GuiEvent = "DoubleClick")
{
    LV_GetText(selectedTitle2, A_EventInfo)
    selectedLink2 := links2[A_EventInfo]
    
    ; 기사 본문 가져오기
    wh.Open("GET", selectedLink2)
    wh.Send()
    articleSource2 := wh.ResponseText()
    articleBody2 := ExtractArticleBody2(articleSource2)

    ; 기사 본문을 보여주는 새 GUI 창 생성
    Gui, 3:Destroy  ; 이전 GUI가 있으면 파괴
    Gui, 3:Add, Text,, % "기사 링크: " selectedLink2
    Gui, 3:Add, Edit, r20 w600, % articleBody2
    Gui, 3:Add, Button, gOpenLink2, 링크 열기
    Gui, 3:Show,, 기사 본문
}
Return

OpenLink2:
{
    ; 클릭 시 기본 웹 브라우저에서 링크 열기
    Run, %selectedLink2%

    ; 링크 열기 버튼 클릭 후 GUI 창 파괴
    Gui, 3:Destroy
}
Return

; GUI 닫기 처리
GuiClose:
ExitApp

 

 

 

 

 

 

프로그램 개발 의뢰 및 문의

검은망치 카카오톡오픈프로필 : https://open.kakao.com/o/sDUaoCNg

 

[오토핫키] 검은망치님의 오픈프로필

오토핫키 개발러

open.kakao.com