Python을 사용하여 웹에서 Word로

반복 작업을 자동화하는 데 있어서 파이톤은 좋은 선택이다.본고에서 우리는 파이톤의 강력한 기능을 이용하여 웹 내용을 캡처하고 양식이 좋은 Word 문서로 전환하는 방법을 연구할 것이다.
계속 읽고 배우는 방법:
  • 사용BeautifulSoup 스크래치 내용
  • 스크래치된 데이터를 Word 형식으로 변환하기 위해 Pandoc 사용
  • 질문 정의


    우리는 우리가 웹 사이트를 하나 가지고 있는데, 그 위에 유형에 따라 조직된 도서 목록이 있다고 가정하자.Word 문서의 디렉터리를 원합니다.이 문제를 해결하는 관건은 두 가지 측면에 있다. (1) 우리는 어떻게 데이터를 수집합니까?(2) 이 데이터에서 Word 문서를 어떻게 만듭니까?
    본 강좌의 예시에서 우리는 다음과 같은 스크래치 연습을 위해 만든 가상 사이트를 사용할 것이다. http://books.toscrape.com/

    다음 단계에서는 이 문제를 해결하는 데 필요한 단계를 요약합니다.
  • 인덱스 페이지
  • 에서 데이터 수집
  • 모든 영화 카테고리 페이지의 링크 목록 찾아보기
  • 각 부문 페이지를 방문하여 해당 부문의 영화를 대략적으로 열거한다
  • 각 유형의 각 영화를 방문하여 해당 영화에 대한 데이터를 얻는다
  • 수집한 데이터를 가격 인하 문자열로 포맷
  • 수집된 데이터를 Word 문서로 저장
  • 색인 페이지에서 데이터 수집


    첫 번째 단계는 색인 페이지에서 데이터를 가져오는 것입니다.
    from urllib.request import urlopen
    from bs4 import BeautifulSoup
    
    
    def collect_website_data(url):
        """
        Takes url string parameter, returns BeautifulSoup object with website content
        """
        index_page = urlopen(url) # HTTP Response
        scrape_data = BeautifulSoup(index_page, "html.parser") # BeatifulSoup Object
        return scrape_data
    
    
    if __name__ == "__main__":
        BASE_URL = "http://books.toscrape.com/"
        page_data = collect_website_data(BASE_URL)
    
    
    위의 스크립트에서 무슨 일이 일어났는지 알아보자.우리는 collect_website_data라는 함수를 정의했다.이 함수는 문자열을 매개 변수로 합니다.이것은 우리가 잡고 싶은 페이지의 URL이길 바랍니다.
    여기에서 우리는 urlopen 라이브러리의 urllib.request 방법을 사용한다.
    그리고 http 응답이 BeautifulSoup 대상으로 변환되어 이제 캡처할 수 있습니다.
    스크립트의 main 부분에서 우리는 collect_website_data 함수를 호출하고 BASE_URL를 매개 변수로 제공한다.

    범주 목록 가져오기


    현재 우리는 웹 페이지 캡처 대상이 생겼으니, 모든 분류 페이지의 목록을 어떻게 얻는지 알아야 한다.
    이를 위해, 우리는 또 다른 함수를 만들었다
    ...
    
    def get_list_of_category_urls(bs_object, base_url):
        """
        Takes a BeautifulSoup object as parameter, returns a list of urls
        """
        category_a_elements = bs_object.find("div", {"class": "side_categories"}).li.ul.findAll("a")
        category_links = []
    
        for item in category_a_elements:
            href = base_url + item.get("href")
            category_links.append(href)
    
        return category_links
    
    
    if __name__ == "__main__":
        ...
        links_to_categories = get_list_of_category_urls(page_data, BASE_URL)
    
    get_list_of_category_urls 두 개의 인자를 받아들인다. 하나는BeautifulSoup 대상이고 하나는기본 URL을 표시하는 문자열이다.
    category 사이드바 부분에 대한 분석 결과<div class="side_categories">에 사이드바 메뉴가 포함되어 있습니다.

    그러나 우리는 하위 원소<ul>에 깊이 들어가 모든 원소<a>를 찾아야 한다.BeautifulSoup을 사용하면 다음과 같은 작업을 수행할 수 있습니다.
    category_a_elements = bs_object.find("div", {"class": "side_categories"}).li.ul.findAll("a")
    
    그 자체가 아름다운 강좌가 아니기 때문이다.더 많은 정보와 예시를 참고하십시오Beautiful documentation.
    다음에 우리는 for를 사용하여 목록의 모든 요소를 순환해서 href 속성을 선택할 것이다.우리의 예시에서 모든 hrefs는 상대적이기 때문에 우리는 모든 BASE_URL 앞에 접두사를 붙여서 절대 링크 목록을 구축해야 한다.
    for item in category_a_elements:
            href = base_url + item.get("href")
            category_links.append(href)
    
    순환마다 href 항목이 category_links = [] 목록에 추가됩니다.모든 범주를 반복한 후 범주 페이지의 전체 URL인 문자열 목록을 반환합니다.
    우리는 목록을 links_to_categories 변수에 저장할 것이다.

    각 범주 페이지에서 데이터 추출


    분류 URL 목록이 완성되면 각 페이지에 액세스하여 원하는 정보를 검색하는 캡처 스크립트를 계속 작성할 수 있습니다.
    각 분류 페이지에서 분류 제목을 가져오는 것과 같은 간단한 작업부터 시작하겠습니다.
    ...
    
    def get_category_titles_from_each_page(list_of_urls):
        """
        Takes a list of urls, returns category titles from each visited page
        """
        titles = []
    
        for url in list_of_urls:
            category_page = urlopen(url)
            scrape_data = BeautifulSoup(
                category_page, "html.parser")  # BeatifulSoup Object
            title = scrape_data.h1.text
            titles.append(title)
    
        return(titles)
    
    
    if __name__ == "__main__":
        ...
        titles = get_category_titles_from_each_page(links_to_categories)
    
    
    links_to_categories의 목록을 입력으로 사용하고 get_category_titles_from_each_page 함수를 실행합니다.
    이 함수는 titles 라는 빈 목록을 사용합니다.그리고 웹 페이지를 반복해서 요청하고 Beautiful Soup 대상으로 변환한 다음 for 표시된 텍스트를 검색하는 과정을 사용합니다.매번 달리기를 할 때마다 우리는 <h1> 목록을 추가한다.함수는 완전한 목록을 되돌려줍니다.

    가격 인하 서식을 적용하다


    다음 단계에서는 레코드 목록을 태그 문자열로 변환합니다.
    왜 값을 내렸습니까?이것은 우리가 원시 텍스트에 간단한 문자열 조작 기술을 적용하여 가격을 내리는 것으로 전환할 수 있도록 한다.그리고 가격 인하 형식은 여러 출력 형식으로 쉽게 변환할 수 있다.
    이 연습에서는 다음과 같은 가격 인하 원칙을 이해해야 합니다.
    # One '#' marks a h1 header
    
    ## Two '#'s mark a h2 header
    
    This will be a paragraph
    
    This will another paragraph
    
    titles 함수의 접두사는 aapply_markdown_formatting이고 그 다음은 a#이며 접두사는 두 개의 새 줄space 문자이다.
    ...
    
    def apply_markdown_formatting(list_of_records):
        """
        Takes an iterable, returns markdown formatted string
        """
        markdown_string = ""
    
        for item in list_of_records:
            line = "#" + " " + item + "\n\n"
            markdown_string += line
    
        return markdown_string
    
    
    if __name__ == "__main__":
        ...
        markdown = apply_markdown_formatting(titles)
    
    
    만약 우리가 운행\n\n한다면 우리는 다음과 같은 결과를 얻어야 한다.
    # Travel
    
    # Mystery
    
    # Historical Fiction
    
    # Sequential Art
    ...
    

    단어로 변환


    태그 문자열을Word 문서로 성공적으로 변환할 수 있는지 확인할 때가 되었습니다.
    이를 위해서는 install pandoc universal document converter가 필요합니다.Pandoc는 Windows, macOS 및 Linux에서 사용할 수 있습니다.Pandoc는 Markdown과 Word에 국한되지 않는 대량의 문서 태그 형식을 지원합니다.
    스크립트 자체에서, 우리는 print(markdown_string) 라이브러리를 사용할 것입니다. 이것은 판독에 얇은 포장을 제공합니다.Word 출력에 페이지 나누기를 삽입할 수 있는 pypandoc 라는 추가 필터를 설치하기를 원할 수도 있습니다.이 두 소프트웨어 패키지는pypi에서 제공되며 pip를 통해 설치할 수 있습니다.
    ...
    import pypandoc
    ...
    
    def convert_markdown_to_docx(markdown_string):
        """
        Takes a markdown string, converts it to docx
        """
        filters = ['pandoc-docx-pagebreakpy']
        output = pypandoc.convert_text(
            markdown_string, 'docx', format='md', outputfile="output.docx", filters=filters)
        pass
    
    
    if __name__ == "__main__":
        ...
        convert_markdown_to_docx(markdown)
    
    봐라!우리는 이미 데이터를 캡처해서 Word 문서를 만들었습니다!pandoc-docx-pagebreakpy 파일에는 output.docx 형식의 필름 종류 목록이 포함되어 있어야 합니다.
    이것은 웹-to-docx 스크립트에 기본적인 기능을 제공하지만, 조금만 더 추가합시다.

    더욱 복잡한 예


    다음 함수Heading 1를 고려하면 get_info_for_each_filmget_category_titles_from_each_page의 기능을 결합시켰다.우리는 apply_markdown_formattingcollect_website_data 그리고 get_list_of_category_urls 함수를 다시 사용할 것이다.
    import progressbar
    import pypandoc
    from urllib.request import urlopen
    from bs4 import BeautifulSoup
    
    
    def collect_website_data(url):
        ...
        return scrape_data
    
    
    def get_list_of_category_urls(bs_object, base_url):
        ...
        return category_links
    
    
    def get_info_for_each_film(list_of_urls, base_url):
        """
        Takes a list of urls, returns markdown formatted string
        """
        markdown_string = ""
    
        print('Retrieving film data for each category:')
        with progressbar.ProgressBar(max_value=len(list_of_urls)) as bar:
            for counter, url in enumerate(list_of_urls):
                category_page = urlopen(url)
                scrape_data = BeautifulSoup(
                    category_page, "html.parser")
                category = scrape_data.h1.text
                category_md = "#" + " " + category + "\n\n"
                markdown_string += category_md
                links_to_films = scrape_data.find_all("h3")
                links_to_films = [base_url + "catalogue/" +
                                  i.a.get("href")[9:] for i in links_to_films]
                for film_link in links_to_films:
                    film_page = urlopen(film_link)
                    scrape_data = BeautifulSoup(
                        film_page, "html.parser")
                    film_title = scrape_data.h1.text
                    film_title_md = "##" + " " + film_title + "\n"
                    markdown_string += film_title_md
                    try:
                        description = scrape_data.find(
                            "div", {"id": "product_description"}).next_sibling.next_sibling.text
                        description_md = description + "\n\n"
                        markdown_string += description_md
                    except AttributeError as e:
                        markdown_string += '\n\n'
                markdown_string += '\\newpage'
                bar.update(counter)
        return markdown_string
    
    
    def convert_markdown_to_docx(markdown_string):
        ...
        pass
    
    
    if __name__ == "__main__":
        BASE_URL = "http://books.toscrape.com/"
        page_data = collect_website_data(BASE_URL)
        links_to_categories = get_list_of_category_urls(page_data, BASE_URL)
        film_data = get_info_for_each_film(links_to_categories, BASE_URL)
        convert_markdown_to_docx(film_data)
    
    
    상기 함수는 유효한 태그 문자열을 한꺼번에 만들 수 있도록 필요한 웹 캡처와 문자열 형식 설정을 실행합니다.
    스크립트가 실행되는 데 시간이 걸리기 때문에, 나는 convert_markdown_to_docx 라이브러리에 프로그레스바를 추가했다.진행률 표시줄은 범주 URL이 포함된 목록의 길이를 사용하여 진행률 증가 값의 최대 범위를 설정합니다.progressbar2 방법은 enumerate에 계수기를 순환적으로 추가하여 줄의 진도를 높일 수 있다.
    극본을 더욱 유용하게 하기 위해서 우리는 각 영화의 각 유형에서 데이터를 추출할 수 있다.목표는 다음 패턴을 따르는 문서를 만드는 것입니다.
    [Heading 1] -- Category
        [Heading 2] -- Title
            [Paragraph] -- Film description
    
    각 카테고리는 afor, 각 영화 제목은 aHeading 1가 된다.우리는 또한 Heading 2와 스크랩 설명을 추가할 것이다.
    이를 위해서는 각 분류 페이지에 영화의 URL을 나열해야 합니다.밑바닥 html에 대한 분석에 따르면 영화에 대한 링크는 분류 페이지의 Paragraph 요소에 포함된다.첫 번째 단계는 모든 h3 요소를 검색하는 것이다.영화 페이지의 URL을 얻기 위해 목록 이해를 사용했는데, 이것은 간결하기 위해 일부 코드의 가독성을 희생할 수 있습니다.
    links_to_films = scrape_data.find_all("h3")
    links_to_films = [base_url + "catalogue/" + i.a.get("href")[9:] for i in links_to_films]
    
    여기서 무슨 일이 일어났는지 봅시다. h3 의 모든 항목에 대해 links_to_films 표시에서 href 속성을 가져오고, 문자열에서 시작하여 문자를 잘라내고 (이 문자는 링크의 상대적인 URL 문자를 가리킨다) a 변수에'catalog/'를 붙인다.이렇게 하면 영화 페이지 URL 목록이 작성됩니다. 즉,
    [
    ...
    "http://books.toscrape.com/catalogue/emma_17/index.html",
    "http://books.toscrape.com/catalogue/alice-in-wonderland-alices-adventures-in-wonderland-1_5/index.html"
    ...
    ]
    
    네스트base_url 루프를 사용하면 각 필름 페이지로 이동하여 데이터를 추출할 수 있습니다.BeautifulSoup documentation에서 일부 Beautiful Soup 사기극을 해석했다. 예를 들어 본 예의 Doublefor:
    description = scrape_data.find(
                            "div", {"id": "product_description"}).next_sibling.next_sibling.text
    
    요컨대, 단일 next_sibling 은 요소 사이의 공백만 검색한다.두 번째next_sibling는 영화 묘사를 저장하는next_sibling 요소를 정확하게 검색했다.
    나는 영화가 묘사하지 않은 상황을 처리하기 위해 p 스크레이퍼 주위에 Try/Except 블록을 추가했다.
    Pandoc를 사용하여 Word 문서로 내보낼 때 description 탭에서 설치를 요구합니다. \\newpageGithub에서 전체 스크립트를 확인하신 것을 환영합니다.

    파프스트 메스트 / 문서로 네트워크 연결



    문서로 네트워크 연결


    웹 페이지에서 내용을 추출하여 태그 문자열로 변환하고 Word 문서를 출력하는python 스크립트
    Python 3.6.12를 사용합니다.
    층계
  • 인덱스 페이지
  • 에서 데이터 수집
  • 모든 영화 카테고리 페이지의 링크 목록 찾아보기
  • 각 부문 페이지를 방문하여 해당 부문의 영화를 대략적으로 열거한다
  • 각 유형의 각 영화를 방문하여 해당 영화에 대한 데이터를 얻는다
  • 수집한 데이터를 가격 인하 문자열로 포맷
  • 수집된 데이터를 Word 문서로 저장
  • Dev.to에 대한 기사 보기 --

    의존 관계


    외부 의존

  • Pandoc document converter
  • 외부 Python 라이브러리 사용

  • BeautifulSoup 3.2.2
  • pypandoc 1.5
  • pandoc-docx-pagebreak 0.0.2
  • progressbar2 3.53.1
  • View on GitHub

    이 해결 방안의 실제 응용


    이 글을 쓰는 영감은 내가 최근에 어쩔 수 없이 해결해야 할 문제에서 나온 것이다.일상적인 업무에서 저는 대형 대학의 IT 비즈니스 분석가입니다.그 중 한 행정 사무실은 워드 문서를 만드는 방법을 개선하기 위해 도움을 요청했다. 이 문서는 과정 사이트에서 제공하는 대학원 과정 데이터의 내보내기를 포함한다.
    파일을 생성하는 과정은 한 직원이 약 200페이지의 수업 페이지를 자세히 읽고 수업 정보를 복사하여 Word 파일에 붙여넣어야 한다.이 워드 파일은 대학원생 모집 설명서 인쇄판의 출처가 될 것이다.
    반복적인 실험을 통해 상술한 방법이 효과를 거두었고 나는 마침내 대체적으로 다음과 같은 구조의 Word 문서를 얻었다.
    [Heading 1] -- Faculty
        [Heading 2] -- School
            [Heading 3] -- Course title
                [Paragraph] -- Course details
                [Paragraph] -- Course description
                [Paragraph] -- Course requirements
    
    최종 출력 파일은 관련 사무실의 호평을 받았고 나도 괜찮은 피드백을 받았다😄:

    As Clarke once put it: "Any sufficiently advanced technology is indistinguishable from magic.", and this is magic, it will be of huge assistance for the development of the prospectus.


    약간의 프로그래밍이 한 사람의 생활을 더욱 가볍게 할 수 있다는 것을 보니 매우 기쁘다.
    네가 가기 전에...만약 당신이 이 글을 좋아한다면Follow 단추를 눌러 주십시오.생각해봐.안녕히 계세요.

    좋은 웹페이지 즐겨찾기