输入关键字 抓取所有网页(一个神器之一selenium五年发表文章五年数量)

优采云 发布时间: 2022-02-02 14:03

  输入关键字 抓取所有网页(一个神器之一selenium五年发表文章五年数量)

  PubMed 是一个用于生物医学文章搜索和摘要的免费搜索数据库。它是一个网站,经常用于查找生物学文献。最近学了爬虫相关的知识包括urllib库、requests库、xpath表达式、scrapy框架等。正想着去爬PubMed,就动手实践一下,准备爬上文章发表的数PubMed根据过去五年的关键词搜索,并以此为依据看过去五年的研究方向。程度。

  最初的想法是使用scrapy框架进行爬取和存储。于是打开PubMed,开始分析网页构成、源码等。发现NCBI使用的是动态网页,在进行翻页、搜索关键字等操作时,URL并没有变化。于是想到了爬虫神器之一的selenium模块,用selenium来模拟搜索、翻页等操作,然后分析源码得到想要的信息。由于和selenium接触不多,所以暂时在网上找了一些功能。

  1、 加载需要的模块

  import urllib

import time

import matplotlib.pyplot as plt

import numpy as np

from lxml import etree

from selenium import webdriver

from selenium.webdriver.support import expected_conditions as EC

from selenium.webdriver.common.by import By

from selenium.webdriver.support.ui import WebDriverWait

from selenium.common.exceptions import TimeoutException

from collections import Counter

  2、从关键字构造 URL

  手动输入几个关键字,分析 URL 的结构。

  PubMed 的原创链接是 '',当输入和搜索 'cancer,TCGA,Breast' 时,url 变为 ''。所以不难分析,URL由两部分组成,一部分是同一个'',另一部分是由我们搜索的关键字拼接而成的字符串'%2C'组成的。因此,对于传入的‘keyword’,我们可以做如下处理,拼接到搜索后返回的url中

  keyword = '%2C'.join(keyword)

tart_url = 'https://www.ncbi.nlm.nih.gov/pubmed/?term='

url = start_url + keyword

  这样,我们简单地连接返回的 url。

  3、创建浏览器对象

  接下来就是使用selenium模块打开我们的Chrome浏览器,跳转到url界面。这个操作相信大家都很熟悉了。因为后面要模拟点击和翻页,所以需要实例化一个WebDriverWait对象,方便后续调用

  browser = webdriver.Chrome()

self.browser.get(url)

wait = WebDriverWait(browser, 10)

  模拟点击网页

  打开网页后,我们需要模拟点击网页。首先,我们需要找到过去五年的文章,所以我们需要模拟点击左侧5years的按钮,改变单页显示的文章个数。变成200,这样可以减少我们的翻页操作

  

  QQ图片246.png

  在我们模拟点击之前,我们必须等到网页上加载了相应的元素才能点击,所以我们需要使用前面提到的WebDriverWait对象。代码显示如下

  years =wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#_ds1 > li > ul > li:nth-child(1) > a')))

years.click()

perpage = self.wait.until(EC.element_to_be_clickable((By.XPATH,'//ul[@class="inline_list left display_settings"]/li[3]/a/span[4]')))

perpage.click()

page_200 = self.wait.until(EC.element_to_be_clickable(

(By.CSS_SELECTOR, '#display_settings_menu_ps > fieldset > ul > li:nth-child(6) > label')))

  此处使用了 CSS 选择器和 Xpath 表达式。用哪一种就看个人喜好了,用哪一种方便都可以。EC.element_to_be_clickable 是在一个元组中传递的,第一个元素是声明要使用的选择器,第二个元素是表达式,这个函数的意思是等到你在表达式中传递的元素在网页上的使用过程中selenium,有很多地方我们需要用到类似的操作比如presence_of_element_located、text_to_be_present_in_element等,有兴趣的可以去网上一探究竟。

  解析网页并提取信息

  下一步是解析网页。我在这里使用 lxml 来解析网页并从 Xpath 中提取信息。代码如下

  html = self.browser.page_source

doc = etree.HTML(self.html)

self.art_timeanddoi = self.doc.xpath('//div[@class="rprt"]/div[2]/div/p[@class="details"]/text()')

for i in self.art_timeanddoi:

self.yearlist.append(i[2:6])

for i in self.yearlist:

if re.match('2', i):

continue

else:

self.yearlist.remove(i)

  这里主要是对网页中的年份进行Xpath提取和字符串切片处理,从而获取年份信息并存入列表中。在实际操作过程中,发现了少量其他不相关的元素。仔细排查,发现是网页源代码有问题。因此,执行了一个常规过程来删除不以“2”开头的元素。经检查,最终结果是正确的。.

  这里我们提取单页信息。

  执行翻页

  我们还需要经过一个翻页操作来获取我们想要的所有信息。仍然使用 selenium 模块。

  status = True

def next_page():

try:

self.nextpage = self.wait.until(

EC.element_to_be_clickable((By.XPATH, '//*[@title="Next page of results"]')))

except TimeoutException:

status = False

while True:

if status:

next_page()

else:

break

  这里我先定义一个判断是否可以翻页的函数,并使用异常捕获,因为翻页动作到最后一页就应该停止,不能再次点击翻页元素。因此,在进行点击操作时应先进行判断。如果不能点击,会因为超时而抛出异常。next_page 函数中的status 变量记录是否可以点击“下一页”按钮。接下来是一个 while True 循环。翻页动作只会在 next_page 变为 False 时停止。在循环中,我们不断地解析网页以提取信息以获得所有想要的信息。

  视觉处理

  爬取了全年信息列表后,还需要进一步的可视化处理,直观判断目标课题的研究趋势。因此,我们使用matplotlib进行可视化操作,简单地画一个折线图。代码显示如下:

   def plot_curve(yearlist):

counter = Counter(yearlist)

dic = dict(counter)

keys = sorted(list(dic.keys()))

curcount = 0

y = []

temp = [int(i) for i in keys]

for i in range(min(temp), max(temp)+1):

if str(i) in keys:

curcount += self.dic[str(i)]

y.append(self.curcount)

else:

y.append(self.curcount)

plt.figure(figsize=(8, 5))

plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签

plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

plt.xlabel('年份')

plt.ylabel('近五年文章数量')

plt.plot(np.arange(min(temp), max(temp)+1), np.array(y), 'r', marker='+', linewidth=2)

plt.show()

  最后粘贴完整代码:

  import re

import urllib

import time

import numpy as np

from lxml import etree

from selenium import webdriver

from selenium.webdriver.support import expected_conditions as EC

from selenium.webdriver.common.by import By

from selenium.webdriver.support.ui import WebDriverWait

from selenium.common.exceptions import TimeoutException

from collections import Counter

import matplotlib.pyplot as plt

class NcbiInfo(object):

browser = webdriver.Chrome()

start_url = 'https://www.ncbi.nlm.nih.gov/pubmed/?term='

wait = WebDriverWait(browser, 10)

def __init__(self, keywordlist):

self.temp = [urllib.parse.quote(i) for i in keywordlist]

self.keyword = '%2C'.join(self.temp)

self.title = ' AND '.join(self.temp)

self.url = NcbiInfo.start_url + self.keyword

self.headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'}

self.file = open('information.txt', 'w')

self.status = True

self.yearlist = []

def click_yearandabstract(self, ):

self.browser.get(self.url)

years = self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#_ds1 > li > ul > li:nth-child(1) > a')))

years.click()

perpage = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//ul[@class="inline_list left display_settings"]/li[3]/a/span[4]')))

perpage.click()

page_200 = self.wait.until(EC.element_to_be_clickable(

(By.CSS_SELECTOR, '#display_settings_menu_ps > fieldset > ul > li:nth-child(6) > label')))

page_200.click()

def get_response(self):

self.html = self.browser.page_source

self.doc = etree.HTML(self.html)

def get_numof_article(self):

article_count_ = self.doc.xpath('//*[@id="maincontent"]/div/div[3]/div[1]/h3/text()')[0]

if 'of' not in article_count_:

print(article_count_.split(': ')[1])

else:

print(article_count_.split('of ')[1])

def get_info(self):

self.art_timeanddoi = self.doc.xpath('//div[@class="rprt"]/div[2]/div/p[@class="details"]/text()')

for i in self.art_timeanddoi:

self.yearlist.append(i[2:6])

for i in self.yearlist:

if re.match('2', i):

continue

else:

self.yearlist.remove(i)

def next_page(self):

try:

self.nextpage = self.wait.until(

EC.element_to_be_clickable((By.XPATH, '//*[@title="Next page of results"]')))

except TimeoutException:

self.status = False

def plot_curve(self):

self.counter = Counter(self.yearlist)

self.dic = dict(self.counter)

self.keys = sorted(list(self.dic.keys()))

self.curcount = 0

self.y = []

temp = [int(i) for i in self.keys]

for i in range(min(temp), max(temp)+1):

if str(i) in self.keys:

self.curcount += self.dic[str(i)]

self.y.append(self.curcount)

else:

self.y.append(self.curcount)

plt.figure(figsize=(8, 5))

plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签

plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

plt.xlabel('年份')

plt.ylabel('近五年文章数量')

plt.title(self.title)

plt.plot(np.arange(min(temp), max(temp)+1), np.array(self.y), 'r', marker='+', linewidth=2)

plt.show()

def main(self):

self.click_yearandabstract()

time.sleep(3)

self.get_response()

self.get_numof_article()

while True:

self.get_info()

self.next_page()

if self.status:

self.nextpage.click()

self.get_response()

else:

break

self.plot_curve()

if __name__ == '__main__':

a = NcbiInfo(['TCGA', 'breast', 'cancer'])

a.main()

  结果如下:

  

  图像.png

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线