Python에서 ResearchGate 검색의 모든 질문을 웹 스크래핑

  • Intro
  • What will be scraped
  • Prerequisites
  • Full Code
  • Links

  • 소개



    현재 ResearchGate 검색 - 질문 페이지에서 데이터 추출을 지원하는 API가 없습니다.

    이 블로그 게시물은 적절한 API를 출시하는 동안 아래에 제공된 DIY 솔루션을 사용하여 직접 할 수 있는 방법을 보여주기 위한 것입니다.

    이 솔루션은 당사Legal US Shield에 대해 제공하는 paid production and above plans을 포함하지 않고, 예를 들어 CAPTCHA와 같은 블록을 우회해야 하는 등의 제한 사항이 있으므로 개인 용도로 사용할 수 있습니다.

    공개 로드맵을 확인하여 이 API에 대한 프로세스를 추적할 수 있습니다.

    🗺 [New API] ResearchGate Search: Publications, Authors, Questions

    스크랩 할 것





    전제 조건



    CSS 선택자를 사용한 기본 지식 스크래핑

    CSS 선택기로 스크랩하지 않은 경우 그것이 무엇인지, 장단점, 웹 스크래핑 관점에서 왜 중요한지, 그리고 가장 일반적인 접근 방식을 보여주는 전용 블로그 게시물how to use CSS selectors when web-scraping이 있습니다. 웹 스크래핑 시 CSS 선택기를 사용합니다.

    별도의 가상 환경

    이전에 가상 환경으로 작업한 적이 없다면 내 전용 블로그 게시물Python virtual environments tutorial using Virtualenv and Poetry을 살펴보고 익숙해지십시오.

    차단될 확률 감소

    요청이 차단될 가능성이 있습니다. how to reduce the chance of being blocked while web-scraping을 살펴보십시오. 대부분의 웹사이트에서 차단을 우회하는 11가지 방법이 있습니다.

    📌참고: 이것은 이 블로그 게시물에 대한 엄격한 요구 사항이 아닙니다.

    라이브러리 설치:

    pip install parsel playwright
    


    전체 코드




    from parsel import Selector
    from playwright.sync_api import sync_playwright
    import json
    
    
    def scrape_researchgate_questions(query: str):
        with sync_playwright() as p:
    
            browser = p.chromium.launch(headless=True, slow_mo=50)
            page = browser.new_page(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36")
    
            questions = []
            page_num = 1
    
            while True:
                page.goto(f"https://www.researchgate.net/search/question?q={query}&page={page_num}")
                selector = Selector(text=page.content())
    
                for question in selector.css(".nova-legacy-c-card__body--spacing-inherit"):
                    title = question.css(".nova-legacy-v-question-item__title .nova-legacy-e-link--theme-bare::text").get().title()
                    title_link = f'https://www.researchgate.net{question.css(".nova-legacy-v-question-item__title .nova-legacy-e-link--theme-bare::attr(href)").get()}'
                    question_type = question.css(".nova-legacy-v-question-item__badge::text").get()
                    question_date = question.css(".nova-legacy-v-question-item__meta-data-item:nth-child(1) span::text").get()
                    snippet = question.css(".redraft-text::text").get()
    
                    views = question.css(".nova-legacy-v-question-item__metrics-item:nth-child(1) .nova-legacy-e-link--theme-bare::text").get()
                    views_link = question.css(".nova-legacy-v-question-item__metrics-item:nth-child(1) .nova-legacy-e-link--theme-bare::attr(href)").get()
    
                    answer = question.css(".nova-legacy-v-question-item__metrics-item+ .nova-legacy-v-question-item__metrics-item .nova-legacy-e-link--theme-bare::text").get()
                    answer_link = question.css(".nova-legacy-v-question-item__metrics-item+ .nova-legacy-v-question-item__metrics-item .nova-legacy-e-link--theme-bare::attr(href)").get()
    
                    questions.append({
                        "title": title,
                        "link": title_link,
                        "snippet": snippet,
                        "question_type": question_type,
                        "question_date": question_date,
                        "views": {
                            "views_count": views,
                            "views_link": views_link
                            },
                        "answer": {
                            "answer_count": answer,
                            "answers_link": answer_link
                        }
                    })
    
                print(f"page number: {page_num}")
    
                # checks if next page arrow key is greyed out `attr(rel)` (inactive) and breaks out of the loop
                if selector.css(".nova-legacy-c-button-group__item:nth-child(9) a::attr(rel)").get():
                    break
                else:
                    page_num += 1
    
    
            print(json.dumps(questions, indent=2, ensure_ascii=False))
            browser.close()
    
    
    scrape_researchgate_questions(query="coffee")
    


    코드 설명



    라이브러리 가져오기:

    from parsel import Selector
    from playwright.sync_api import sync_playwright
    import json
    



    암호
    설명


    parsel
    HTML/XML 문서를 구문 분석합니다. XPath를 지원합니다.

    playwright
    브라우저 인스턴스로 페이지를 렌더링합니다.
    jsonPython 사전을 JSON 문자열로 변환합니다.


    함수를 정의하고 context manager::으로 playwright를 엽니다.

    scrape_researchgate_questions(query="coffee"):
        with sync_playwright() as p:
            # ...
    



    암호
    설명

    query: str파이썬에게 querystr 가 되어야 한다고 알려줍니다.


    브라우저 인스턴스를 실행하고 new_page를 통과하여 엽니다user-agent.

    browser = p.chromium.launch(headless=True, slow_mo=50)
    page = browser.new_page(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36")
    



    암호
    설명


    p.chromium.launch()
    Chromium 브라우저 인스턴스를 시작합니다.

    headless
    기본 값이더라도 헤드리스 모드에서 실행하도록 명시적으로 지시합니다playwright.

    slow_mo
    실행 속도를 늦추라고 지시합니다playwright.

    browser.new_page()
    새 페이지를 엽니다. user_agent는 실제 사용자가 브라우저에서 요청을 수행하는 데 사용됩니다. 사용하지 않으면 기본적으로 playwright 값인 None 가 됩니다. Check what's your user-agent .


    임시 목록을 추가하고, while 루프를 설정하고, 새 URL을 엽니다.

    questions = []
    
    while True:
        page.goto(f"https://www.researchgate.net/search/question?q={query}&page={page_num}")
        selector = Selector(text=page.content())
        # ...
    



    암호
    설명

    goto()전달된 쿼리 및 페이지 매개변수를 사용하여 특정 URL을 요청합니다.
    Selector()반환된 HTML 데이터를 page.content()로 전달하고 처리합니다.


    각 페이지에서 작성자 결과를 반복하고 데이터를 추출하고append 임시list로:

    for question in selector.css(".nova-legacy-c-card__body--spacing-inherit"):
        title = question.css(".nova-legacy-v-question-item__title .nova-legacy-e-link--theme-bare::text").get().title()
        title_link = f'https://www.researchgate.net{question.css(".nova-legacy-v-question-item__title .nova-legacy-e-link--theme-bare::attr(href)").get()}'
        question_type = question.css(".nova-legacy-v-question-item__badge::text").get()
        question_date = question.css(".nova-legacy-v-question-item__meta-data-item:nth-child(1) span::text").get()
        snippet = question.css(".redraft-text::text").get()
    
        views = question.css(".nova-legacy-v-question-item__metrics-item:nth-child(1) .nova-legacy-e-link--theme-bare::text").get()
        views_link = question.css(".nova-legacy-v-question-item__metrics-item:nth-child(1) .nova-legacy-e-link--theme-bare::attr(href)").get()
    
        answer = question.css(".nova-legacy-v-question-item__metrics-item+ .nova-legacy-v-question-item__metrics-item .nova-legacy-e-link--theme-bare::text").get()
        answer_link = question.css(".nova-legacy-v-question-item__metrics-item+ .nova-legacy-v-question-item__metrics-item .nova-legacy-e-link--theme-bare::attr(href)").get()
    
        questions.append({
            "title": title,
            "link": title_link,
            "snippet": snippet,
            "question_type": question_type,
            "question_date": question_date,
            "views": {
                "views_count": views,
                "views_link": views_link
                },
            "answer": {
                "answer_count": answer,
                "answers_link": answer_link
            }
        })
    
    



    암호
    설명

    css()
    to parse data from the passed CSS selector(s) . 후드 아래의 모든 CSS query traslates to XPath using csselect package.
    ::text/::attr(attribute)
    to extract textual or attribute data 노드에서.
    get()/getall()
    to get actual data from a matched node , 또는 get a list of matched data from nodes .
    xpath("normalize-space()")빈 텍스트 노드도 구문 분석합니다. 기본적으로 빈 텍스트 노드는 XPath에서 건너뜁니다.


    다음 페이지가 있는지 확인하고 페이지를 매깁니다.

    # checks if the next page arrow key is greyed out `attr(rel)` (inactive) -> breaks out of the loop
    if selector.css(".nova-legacy-c-button-group__item:nth-child(9) a::attr(rel)").get():
        break
    else:
        page_num += 1
    


    추출된 데이터 및 close 브라우저 인스턴스 인쇄:

    print(json.dumps(publications, indent=2, ensure_ascii=False))
    
    browser.close()
    
    # call the function
    scrape_researchgate_questions(query="coffee")
    


    JSON 출력의 일부:

    [
      {
        "title": "Any Recommendations On An Inexpensive Coffee Grinder To Grind Up Bark Samples To Measure Ph?",
        "link": "https://www.researchgate.netpost/Any_recommendations_on_an_inexpensive_coffee_grinder_to_grind_up_bark_samples_to_measure_pH?_sg=tsmZvLsXrFpn6TG77ljxS8pVJhdOMYVlqqYhQl0BszqPCDW1__lnpczwZl8XJiVROJ8_8G8jaerzpX8",
        "snippet": "We are folloiwng protocol by Hansen et al. (2015) Sci. Pharm. They recommend a Rancilio coffee grinder but these are several hundred dollars. Hoping to use something a little less expensive.",
        "question_type": "Question",
        "question_date": "Oct 2017",
        "views": {
          "views_count": "97 Views",
          "views_link": "post/Any_recommendations_on_an_inexpensive_coffee_grinder_to_grind_up_bark_samples_to_measure_pH?_sg=tsmZvLsXrFpn6TG77ljxS8pVJhdOMYVlqqYhQl0BszqPCDW1__lnpczwZl8XJiVROJ8_8G8jaerzpX8"
        },
        "answer": {
          "answer_count": "2 Answers",
          "answers_link": "https://www.researchgate.netpost/Any_recommendations_on_an_inexpensive_coffee_grinder_to_grind_up_bark_samples_to_measure_pH?_sg=tsmZvLsXrFpn6TG77ljxS8pVJhdOMYVlqqYhQl0BszqPCDW1__lnpczwZl8XJiVROJ8_8G8jaerzpX8"
        }
      }, ... other questions
      {
        "title": "Are There Any Ways To Find The Concentration Of A Solution Where Its Chemical Formula And Number Of Moles Are Unknown? ",
        "link": "https://www.researchgate.netpost/Are_there_any_ways_to_find_the_concentration_of_a_solution_where_its_chemical_formula_and_number_of_moles_are_unknown?_sg=6W-hvIYx-FRel_YiWd62lbksTzeWP7GVkZ3tVO6SgZI7F_czhLz_oFCduq9DVhrhvIUy97168wXrn30",
        "snippet": "A comprehensive way to find the concentration of random solutions would enhance benefits related with health, industry, technology and commercial aspects. Although beer lambert law is a solution, there are some cases where Epsilon is unknown (Example: A Coca-Cola drink or a cup of coffee). In this cases, proper a​l​t​",
        "question_type": "Question",
        "question_date": "Jan 2022",
        "views": {
          "views_count": "742 Views",
          "views_link": "post/Are_there_any_ways_to_find_the_concentration_of_a_solution_where_its_chemical_formula_and_number_of_moles_are_unknown?_sg=6W-hvIYx-FRel_YiWd62lbksTzeWP7GVkZ3tVO6SgZI7F_czhLz_oFCduq9DVhrhvIUy97168wXrn30"
        },
        "answer": {
          "answer_count": "4 Answers",
          "answers_link": "https://www.researchgate.netpost/Are_there_any_ways_to_find_the_concentration_of_a_solution_where_its_chemical_formula_and_number_of_moles_are_unknown?_sg=6W-hvIYx-FRel_YiWd62lbksTzeWP7GVkZ3tVO6SgZI7F_czhLz_oFCduq9DVhrhvIUy97168wXrn30"
        }
      }
    ]
    


    연결


  • GitHub Gist

  • 가입 |

    Feature Request 💫 또는 Bug 🐞 추가

    좋은 웹페이지 즐겨찾기