使用Scrapy根据DOI下载文献到本地

使用Scrapy根据DOI下载文献到本地

Scrapy框架专门提供了用于文件下载的FilesPipline和用于图片下载的ImagePipline

爬取策略

  1. 从Mysql数据库中提取DOI号
  2. 拼接url:‘http://www.sci-hub.ren/’+doi 指向doi对应的pdf页面
  3. 在该页面中通过xpath和正则表达式,将指向pdf的url提取出来,交付给pipline进行下载

具体步骤

  1. 设置setting.py
    # setting.py
    # 框架自动生成无需修改
    BOT_NAME = 'DoiDown'
    
    SPIDER_MODULES = ['DoiDown.spiders']
    NEWSPIDER_MODULE = 'DoiDown.spiders'
    # 设置USER_AGENT
    USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
    # 不遵从robots协议
    ROBOTSTXT_OBEY = False
    # 设置日志等级
    LOG_LEVEL = 'ERROR'
    # 将日志保存到日志文件
    LOG_FILE = './log.log'
    # 设置下载延迟
    DOWNLOAD_DELAY = 3
    # 开启管道并设置多管道优先级
    ITEM_PIPELINES = {
         
        'DoiDown.pipelines.initPipeline': 200,
        'DoiDown.pipelines.fileDown': 300
    }
    # 设定FilePipline的文件保存路径
    FILES_STORE = './PDF'
    
  2. 定义item
     # items.py
     import scrapy
    
     class DoidownItem(scrapy.Item):
         # define the fields for your item here like:
         # name = scrapy.Field()
         file_urls = scrapy.Field()
         files = scrapy.Field()
         pass
    
    file_urlsfile都是item的字段。FilesPipline要求file_urls必须是一个列表,存的是待下载文件的url。文件下载完成之后,file包含了文件的路径、文件校验、文件的url等信息。
  3. 编写spider
     # doi_down.py
    
     import pymysql
     import scrapy
     from scrapy import Request
     import re
     from ..items import DoidownItem
    
    
     class DoiDownSpider(scrapy.Spider):
         name = 'doi_down'
         # allowed_domains = ['sci-hub.ren']
         connect = None
         cursor = None
    
         # start_urls = ['http://sci-hub.ren/']
    
         def start_requests(self):
             # 自定义开始爬取的url。spider从这个函数开始执行。
             self.connect = pymysql.connect(
                 host="localhost",
                 port=3306,
                 user="root",
                 passwd="xxxxxx",
                 db="web_of_science")
             self.cursor = self.connect.cursor()
             self.cursor.execute("select doi from wos_document;")
             doi_lists = list(self.cursor.fetchall())
    
             for doi in doi_lists[:50]:
                 if doi[0] is None:
                     print('该DOI为空...')
                 else:
                     detail_url = 'https://www.sci-hub.ren/' + doi[0]
                     print(detail_url)
                     # 发起url请求,并指定处理响应的回调函数
                     yield Request(detail_url, callback=self.parse)
    
             self.connect.close()
    
         def parse(self, response):
             # 该函数用于解析响应数据
             print('解析中!!!')
             detail_url_list = response.xpath('//*[@id="buttons"]/ul/li[2]/a/@onclick')
             item = DoidownItem()
             item['file_urls'] = []
             if len(detail_url_list) == 0:
                 print('*' * 10 + '已自动跳转第三方网站,不予处理!!!' + '*' * 10)
             else:
                 # 提取第一个目标Selector的内容
                 target = detail_url_list.extract_first()
                 find_url = re.compile(r"href='(.*?)'")
                 target_url = re.findall(find_url, target)[0]
                 if target_url[0] != 'h':
                     target_url = 'https:' + target_url
                 item['file_urls'].append(target_url)
                 # 这里解析到了pdf文件对应的url;yield的作用是交付给pipline.py处理
                 yield item
    
    
  4. 自定义pipelines
     
     import re
    
     # useful for handling different item types with a single interface
     from scrapy import Request
     from scrapy.pipelines.files import FilesPipeline
    
    
     class initPipeline:
         def open_spider(self, spider):
             print('*' * 10 + '开始下载...' + '*' * 10)
    
         def process_item(self, item, spider):
             return item
    
         def close_spider(self, spider):
             print('*' * 10 + '爬取完毕' + '*' * 10)
    
    
     class fileDown(FilesPipeline):
         def get_media_requests(self, item, info):
             # 向FilesPipline提交url地址,进行文件下载
             for url in item['file_urls']:
                 yield Request(url)
    
         def file_path(self, request, response=None, info=None):
             # 设置保存的文件名
             find_name = re.compile(r"/(.*?)?download=true")
             file_name = re.findall(find_name, request.url)[0]
             file_name = file_name.split('/')[-1]
             file_name = file_name[0:len(file_name) - 1]
             print(file_name, '正在下载!!!')
             return file_name
    
    之前已经在settings.py中设定了initPipline优先级较高。在initPipline中自定义了一个管道,爬虫程序从open_spider开始执行。然后执行spider,也就是doi_down.py。程序执行完close_spider后 结束。
    使用FilesPipeline下载文件,需要在管道中从scrapy.pipelines.files import进来。然后作为参数传入自定义的用于下载文件的管道类中。fileDownget_media_requests是用于发起下载请求的函数;file_path是用于设定保存文件名的函数。这两个函数的函数名是固定的,也就是说需要用FilesPipeline自定义的管道,要自定义请求的发起和保存的文件名的设定,对应的函数名必须这样命名。
全部评论

相关推荐

#简历#先说一说我自己的想法,很多人都很排斥苍穹外卖,认为没什么技术点和含金量,但实际上我觉得恰恰相反,苍穹外卖虽然代码本身并不是你自身能力的证明,但是是作为一个新人学习时很好的跳板和原始框架,在这个框架上进行的改进可以很好的辐射到你自己的个人成果上,并作为你和面试官聊天的筹码大多数人的苍穹外卖只写增删改查,千篇一律,吸引不了面试官,所以这才让大家误以为只要是苍穹外卖就不要写进简历里这种误区,但实际上如果你在原有的层面上进行改进,并作为你的项目亮点和面试官介绍,告诉他你的苍穹外卖和别人的有什么不同,增加了哪些技术难点,这才显得你是完全自己理解了这个项目,并且有自己动手实践项目的能力,而不是就看了个课程就以为自己会了,就当成自己的了,如此一来,这反而成为你的加分项苍穹外卖为什么看的人最多,说明它好啊,如果它不好,为什么看的人还这么多,想清楚这个逻辑,我觉得要做的最重要的事,就是如何在原有框架上进行改进提效,比起听其他人的话重新搞一个项目性价比高得多,而且我亲测项目并没有成为我找到工作的阻碍,我投的大厂一大半都给我面试了,而且很多不止一个部门,退一万步说,当你手头没有其他项目的时候,有苍穹外卖总比什么都没有的好很多,不需要因为苍穹外卖有任何心理负担关于简历的任何部分都欢迎大家提意见,十分感谢大家,祝大家找实习+秋招顺利上岸,offer拿到手软#简历中的项目经历要怎么写##我的上岸简历长这样##最后再改一次简历##简历##简历被挂麻了,求建议#
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务