zoukankan      html  css  js  c++  java
  • scrapy抓取国家社科基金项目数据库

    1.明确任务

    目标网站:http://fz.people.com.cn/skygb/sk/index.php/Index/seach

    抓取任务:抓取近五年某关键词(例如"能源"、”大数据“等)的搜索结果,抓取内容包括项目编号、项目名称、学科分类等十一个字段。

    2.网站分析

    利用Fiddler工具分析,输入关键词,指定年份后,点击搜索,针对有多页码搜索结果点击下一页,发现此过程共包括一个POST请求和一个GET请求;其中,指定关键词和年份点击搜索的过程为POST请求,点击下一页的过程为GET请求。

    POST请求参数:

    formdata = {
            'xmname': '',
            'xktype': '0',
            'xmtype': '0',
            'cglevel': '0',
            'cbdate ': '0',
            'cgxs': '0',
            'lxtime': '',
            'ssxt': '0',
            'zyzw': '0',
            'dwtype': '0',
            'jxdata': '0',
            'szdq': '0',
            'pznum': '',
            'cgname': '',
            'jxnum': '',
            'cbs': '',
            'xmleader': '',
            'hj': '',
            'gzdw': '',
            'zz': ''
        }

    POST请求目标URL:http://fz.people.com.cn/skygb/sk/index.php/Index/seach

    GET请求只需要指定参数p即可,因此构造GET请求url为:

    n_url = self.url + '?' + 'xmname={}&p={}'.format(formdata['xmname'], self.page)

    其中,xmname为搜索关键词,p为第几页的页码。

    3.代码编写

    3.1 创建scrapy爬虫项目

    创建项目,名为ProSearch,使用命令:

    scrapy startproject ProSearch http://fz.people.com.cn

    3.2 明确抓取字段

    创建爬虫项目后,编写items.py文件,明确待抓取的字段

    # -*- coding: utf-8 -*-
    import scrapy
    class ProsearchItem(scrapy.Item):
    
        # 关键词
        keyword = scrapy.Field()
        # 项目编号
        pronums = scrapy.Field()
        # 项目类别
        protype = scrapy.Field()
        # 学科类别
        subtype = scrapy.Field()
        # 项目名称
        proname = scrapy.Field()
        # 立项时间
        protime = scrapy.Field()
        # 负责人
        leaders = scrapy.Field()
        # 工作单位
        workloc = scrapy.Field()
        # 单位类别
        orgtype = scrapy.Field()
        # 所在省市
        provloc = scrapy.Field()
        # 所属系统
        systloc = scrapy.Field()

    3.3 生成爬虫文件

    在cmd窗口进入到ProSearch项目后,生成爬虫文件。使用命令:

    scrapy genspider SearchPro

    3.4 编写爬虫逻辑

    生成爬虫文件后,来到spiders文件夹下的SearchPro.py文件,开始辨写爬虫逻辑。

    # -*- coding: utf-8 -*-
    import scrapy
    from ProSearch.items import ProsearchItem
    
    class SearchproSpider(scrapy.Spider):
        
        name = 'SearchPro'  # 爬虫名称
        allowed_domains = ['fz.people.com.cn']
        # start_urls = ['http://fz.people.com.cn/skygb/sk/index.php/Index/seach']
        page = 1
    
        # 指定检索关键词
        keywords = ['可持续', '互联网', '大数据', '能源']
        # 角标
        index = 0
        # 年份
        years = 2018
    
        # POST提交参数
        formdata = {
            'xmname': '',
            'xktype': '0',
            'xmtype': '0',
            'cglevel': '0',
            'cbdate ': '0',
            'cgxs': '0',
            'lxtime': '',
            'ssxt': '0',
            'zyzw': '0',
            'dwtype': '0',
            'jxdata': '0',
            'szdq': '0',
            'pznum': '',
            'cgname': '',
            'jxnum': '',
            'cbs': '',
            'xmleader': '',
            'hj': '',
            'gzdw': '',
            'zz': ''
        }
    
        # 参数提交的url
        url = "http://fz.people.com.cn/skygb/sk/index.php/Index/seach"
    
        def start_requests(self):
            """
            POST请求实现一般是重写start_requests函数,指定第一个关键词为默认检索关键词
            :return: 
            """
            self.formdata['xmname'] = '可持续'
            self.formdata['lxtime'] = str(self.years)
            yield scrapy.FormRequest(
                url=self.url,
                formdata=self.formdata,
                callback=self.parse,
                meta={'formdata': self.formdata}
            )
    
        def parse(self, response):
            """
            解析数据
            :param response: 
            :return: 
            """
            if response.meta['formdata']:
                formdata = response.meta['formdata']
    
            # 每行数据所在节点
            try:
                node_list = response.xpath("//div[@class='jc_a']/table/*")[1:]
            except:
                print("关键词‘{}’无搜索结果!".format(formdata['xmname']))
            for node in node_list:
                # 提取数据
                item = ProsearchItem()
                # 关键词
                item['keyword'] = formdata['xmname']
                # 项目编号
                item['pronums'] = node.xpath('./td[1]/span/text()').extract_first()
                # 项目类别
                item['protype'] = node.xpath('./td[2]/span/text()').extract_first()
                # 学科类别
                item['subtype'] = node.xpath('./td[3]/span/text()').extract_first()
                # 项目名称
                item['proname'] = node.xpath('./td[4]/span/text()').extract_first()
                # 立项时间
                item['protime'] = node.xpath('./td[5]/span/text()').extract_first()
                # 负责人
                item['leaders'] = node.xpath('./td[6]/span/text()').extract_first()
                # 工作单位
                item['workloc'] = node.xpath('./td[8]/span/text()').extract_first()
                # 单位类别
                item['orgtype'] = node.xpath('./td[9]/span/text()').extract_first()
                # 所属省市
                item['provloc'] = node.xpath('./td[10]/span/text()').extract_first()
                # 所属系统
                item['systloc'] = node.xpath('./td[11]/span/text()').extract_first()
                yield item
    
            # 匹配下一页的数据
            if '下一页' in response.xpath("//div[@class='page clear']/a").extract():
                self.page += 1
                n_url = self.url + '?' + 'xmname={}&p={}'.format(formdata['xmname'], self.page)
                yield scrapy.Request(url=n_url, callback=self.parse, meta={'formdata': formdata})
    
            # 匹配其他年份的数据
            searcy_year = int(formdata['lxtime'])
            if not searcy_year <= 2014:
                searcy_year -= 1
                formdata['lxtime'] = str(searcy_year)
                print("检索关键词:{}!".format(formdata['xmname']))
                yield scrapy.FormRequest(
                        url=self.url,
                        formdata=formdata,
                        callback=self.parse,
                        meta={'formdata': formdata}
                )
            # 其他关键词搜索
            else:
                self.index += 1
                if not self.index > len(self.keywords)-1:
                    keyword = self.keywords[self.index]
                    print("更新检索关键词为:{}".format(keyword))
    
                    formdata['xmname'] = keyword
                    formdata['lxtime'] = str(self.years)
    
                    yield scrapy.FormRequest(
                            url=self.url,
                            formdata=formdata,
                            callback=self.parse,
                            meta={'formdata': formdata}
                    )

    3.5 编写数据保存逻辑

    本项目用excel对数据进行保存。在pipelines.py文件中编写数据保存的逻辑。

    # -*- coding: utf-8 -*-
    from openpyxl import Workbook
    
    class ProsearchPipeline(object):
    
        def __init__(self):
            # 创建excel表格保存数据
            self.workbook = Workbook()
            self.booksheet = self.workbook.active
            self.booksheet.append(['关键词', '项目编号', '项目类别', '学科类别', '项目名称', '立项时间', '负责人', '工作单位', '单位类别', '所在省市', '所属系统'])
    
        def process_item(self, item, spider):
            
            DATA = [
                item['keyword'], item['pronums'], item['protype'], item['subtype'], item['proname'], item['protime'], item['leaders'], item['workloc'], item['orgtype'], item['provloc'], item['systloc']
            ]
    
            self.booksheet.append(DATA)
            self.workbook.save('./data/ProSearch.xls')
            return item

    3.6 其他细节

    到此基本内容完成,设置一下settings.py文件对细节进行处理基本爬虫就可以运行了。

    处理一:打开pipline通道

    处理二:添加随机请求头并打开下载中间件

    处理三:添加重拾、延时、log级别等

    处理四:编写脚本main.py文件

    scrapy默认使用命令行进行创建、生成、爬去等任务,可尝试在整个项目下编写一个main.py文件,将爬去命令添加到py文件中,直接在编辑器中F5运行。

    下次每次运行main.py文件就可以直接运行了。

     4.完整代码

     完整代码参见github

    
    
  • 相关阅读:
    Python字符串学习相关问题
    Python函数学习遇到的问题
    How to configure ODBC DSN to access local DB2 for Windows
    如何在Eclipse CDT中编译含有多个main函数的项目
    MakeFile 文件的作用
    云技术:负载均衡SLB
    云技术:弹性计算ECS
    《老罗的Android之旅》导读PPT
    服务器集群负载均衡技术
    杭电ACM 1004题
  • 原文地址:https://www.cnblogs.com/pythoner6833/p/10272133.html
Copyright © 2011-2022 走看看