Проблемы с получением результатов Google Scholar с BeautifulSoup - PullRequest
1 голос
/ 16 марта 2020

Я продолжаю анализ, начатый в этом моем предыдущем вопросе . Я получил информацию о конкретных c публикациях рабочих документов в фрейме данных, состоящем из четырех столбцов: год публикации, порядок публикации (порядок публикации для каждого года, совершенно бесполезный в этой ситуации), название и автор. Поэтому я хочу использовать этот фрейм данных, чтобы очистить Google Scholar и получить информацию о количестве цитирований. Поскольку названия некоторых статей немного обобщены c, в некоторых случаях первый результат исследования Google не является фактически тем, что меня интересует. Поэтому, чтобы выполнить более специализированное исследование, при создании ссылки для выполнения В исследование я включил как название, так и автора (ов) каждой статьи. Я следовал за этим потоком при написании кода.

Примечание: поскольку для выполнения этого анализа необходимы истинные имена, я предпочел не создавать пример фрейма данных. Вместо этого я загрузил файл .csv на мой GitHub.

import pandas as pd
import requests
from bs4 import BeautifulSoup as bs
from random import randint
from time import sleep

url = 'https://raw.githubusercontent.com/nicolacaravaggio/working_paper_roma3/master/rm3_working_paper_list.csv'
df = pd.read_csv(url, error_bad_lines = False)

papers = [] 

for index, rows in df.iterrows():  
    list_paper = rows.title + ' ' + rows.author

    papers.append(list_paper)

title_list_gs = []
citations_list_gs = []

with requests.Session() as s:

    for paper in papers: 

            sleep(randint(1,3))

            url = 'https://scholar.google.com/scholar?q=' + paper + '&ie=UTF-8&oe=UTF-8&hl=en&btnG=Search'
            r = s.get(url)
            soup = bs(r.content, 'html.parser')

            title_gs = soup.select_one('h3.gs_rt a').text if soup.select_one('h3.gs_rt a') is not None else 'No title'
            title_list_gs.append(title_gs)

            citations_gs = soup.select_one('a:contains("Cited by")').text if soup.select_one('a:contains("Cited by")') is not None else 'No citation count'
            citations_list_gs.append(citations_gs)

            print('Title:', title_gs, '; Citations:', citations_gs)  

Однако результат, который я получаю из этого скрипта, представляет собой просто список:

Title: No title ; Citations: No Citation count

Я не уверен, что проблема в моем неуклюжем скрипте (возможно) или в тот факт, что Google мешает мне слишком много царапать от ученого. На самом деле, даже сценарий , который я использовал в качестве отправной точки в этой теме, не всегда возвращает ожидаемый результат. Я надеюсь, что кто-то может дать мне какое-то предложение. Заранее спасибо.

1 Ответ

1 голос
/ 18 марта 2020

Звучит так, будто вы запускаете обнаружение ботов Scholars. Исходя из личного опыта использования Google Scholar, 45 секунд достаточно, чтобы избежать обнаружения CAPTCHA и ботов. У меня был скребок, работающий в течение> 3 дней без обнаружения. Если вы все-таки помечены, достаточно подождать около 2 часов, чтобы начать снова. Вот выдержка из моего кода. .

class ScholarScrape():
    def __init__(self):
        self.page = None
        self.last_url = None
        self.last_time = time.time()
        self.min_time_between_scrape = int(ConfigFile.instance().config.get('scholar','bot_avoidance_time'))
        self.header = {'User-Agent':ConfigFile.instance().config.get('scholar','user_agent')}
        self.session = requests.Session()
        pass

    def search(self, query=None, year_lo=None, year_hi=None, title_only=False, publication_string=None, author_string=None, include_citations=True, include_patents=True):
        url = self.get_url(query, year_lo, year_hi, title_only, publication_string, author_string, include_citations, include_patents)
        while True:
            wait_time = self.min_time_between_scrape - (time.time() - self.last_time)
            if wait_time > 0:
                logger.info("Delaying search by {} seconds to avoid bot detection.".format(wait_time))
                time.sleep(wait_time)
            self.last_time = time.time()
            logger.info("SCHOLARSCRAPE: " + url)
            self.page = BeautifulSoup(self.session.get(url, headers=self.header).text, 'html.parser')
            self.last_url = url

            if "Our systems have detected unusual traffic from your computer network" in str(self.page):
                raise BotDetectionException("Google has blocked this computer for a short time because it has detected this scraping script.")

            return

    def get_url(self, query=None, year_lo=None, year_hi=None, title_only=False, publication_string=None, author_string=None, include_citations=True, include_patents=True):
        base_url = "https://scholar.google.com.au/scholar?"
        url = base_url + "as_q=" + urllib.parse.quote(query)

        if year_lo is not None and bool(re.match(r'.*([1-3][0-9]{3})', str(year_lo))):
            url += "&as_ylo=" + str(year_lo)

        if year_hi is not None and bool(re.match(r'.*([1-3][0-9]{3})', str(year_hi))):
            url += "&as_yhi=" + str(year_hi)

        if title_only:
            url += "&as_yhi=title"
        else:
            url += "&as_yhi=any"

        if publication_string is not None:
            url += "&as_publication=" + urllib.parse.quote('"' + str(publication_string) + '"')

        if author_string is not None:
            url += "&as_sauthors=" + urllib.parse.quote('"' + str(author_string) + '"')

        if include_citations:
            url += "&as_vis=0"
        else:
            url += "&as_vis=1"

        if include_patents:
            url += "&as_sdt=0"
        else:
            url += "&as_sdt=1"

        return url

    def get_results_count(self):
        e = self.page.findAll("div", {"class": "gs_ab_mdw"})
        try:
            item = e[1].text.strip()
        except IndexError as ex:
            if "Our systems have detected unusual traffic from your computer network" in str(self.page):
                raise BotDetectionException("Google has blocked this computer for a short time because it has detected this scraping script.")
            else:
                raise ex

        if self.has_numbers(item):
            return self.get_results_count_from_soup_string(item)
        for item in e:
            item = item.text.strip()
            if self.has_numbers(item):
                return self.get_results_count_from_soup_string(item)
        return 0

    @staticmethod
    def get_results_count_from_soup_string(element):
        if "About" in element:
            num = element.split(" ")[1].strip().replace(",","")
        else:
            num = element.split(" ")[0].strip().replace(",","")
        return num

    @staticmethod
    def has_numbers(input_string):
        return any(char.isdigit() for char in input_string)


class BotDetectionException(Exception):
    pass

if __name__ == "__main__":
    s = ScholarScrape()
    s.search(**{
        "query":"\"policy shaping\"",
        # "publication_string":"JMLR",
        "author_string": "gilboa",
        "year_lo": "1995",
        "year_hi": "2005",

    })
    x = s.get_results_count()
    print(x)

Этот вопрос может содержать больше информации, чтобы помочь вам

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...