财政部ppp数据库爬虫

需求

给出关键字,然后爬取财政部ppp数据库中相应项目的数据,保存到sqlite中。
使用软件:requests、json、sqlite
代码写于2020-4-22,以后可能会出现网页改版而导致不可用
先上代码:

import requests
import json
import sqlite3

db = sqlite3.connect('./caizhengbu.db')
cursor = db.cursor()
cursor.execute('create table if not exists ppp (项目名 TEXT)')
db.commit()

def ppp():
    headers = {# POST /api/pub/project/search-store HTTP/1.1
        'Host': 'www.cpppc.org:8082',
        'Connection': 'keep-alive',
        'Content-Length': '167',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36',
        'Content-Type': 'application/json',
        'Accept': '*/*',
        'Origin': 'https://www.cpppc.org:8082',
        'Sec-Fetch-Site': 'same-origin',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Dest': 'empty',
        'Referer': 'https://www.cpppc.org:8082/inforpublic/homepage.html',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9'
        }

    total_num = None
    cur_num = 0
    pageNum = 1
    while True:
        # payloadData = {"name":"医疗","industry":"",
        #                 "min":0,"max":10000000000000000,
        #                 "pageNumber":pageNum,"size":5,"level":"","start":"","end":"","dist_province":"","dist_city":"","dist_code":""}
        # 选择领域中,医疗卫生是016,准备阶段的代码是status,1是准备,2是采购,3是执行
        payloadData = {"name":"","industry":["016"],"min":0,"max":10000000000000000,
                        "pageNumber":1,"size":5,"status":["3"],"level":"",
                        "start":"","end":"","dist_province":"",
                        "dist_city":"","dist_code":"","created_date_order":"desc"}

        # 储备清单和管理器项目区别在search还是search-store
        r = requests.post('https://www.cpppc.org:8082/api/pub/project/search', 
                        data = json.dumps(payloadData),
                        headers = headers)
        # print(r.text)
        js = json.loads(r.text)
        # js['data']中有total,代表检索出来结果数量
        total_num = int(js['data']['total'])
        for dt in js['data']['hits']:
            proj_id = dt['proj_rid']
            get_single_project(db, cursor, proj_id=proj_id)
            cur_num += 1
        pageNum += 1
        if cur_num >= total_num:
            break

def get_single_project(db: sqlite3.Connection, cursor: sqlite3.Cursor, proj_id = '3a8d834ef9fe41bba342f48d9ca00d33'):
    headers = {
        'Host': 'www.cpppc.org:8082',
        'Connection': 'keep-alive',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36',
        'Content-Type': 'application/json',
        'Accept': '*/*',
        'Sec-Fetch-Site': 'same-origin',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Dest': 'empty',
        'Referer': 'https://www.cpppc.org:8082/inforpublic/homepage.html',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9',
    }
    # url = 'https://www.cpppc.org:8082/api/pub/project/prepare-detail/f7e66ad9651f4193942952fb3fc928d2'
    url = 'https://www.cpppc.org:8082/api/pub/project/prepare-detail/' + proj_id
    r = requests.get(url, headers = headers)
    # print(r.text)
    # detail_url = 'https://www.cpppc.org:8082/api/pub/project/detail/f7e66ad9651f4193942952fb3fc928d2'
    detail_url = 'https://www.cpppc.org:8082/api/pub/project/detail/' + proj_id
    r = requests.get(detail_url, headers = headers)
    print(r.text)
    dt = json.loads(r.text)['data']
    def returnMode(i):
        return ["政府付费", "使用者付费", "可行性缺口补助"][int(i)-1]
    def operateMode(i):
        return ["BOT","TOT","ROT","BOO","TOT+BOT","TOT+BOO","OM","MC","其他"][int(i) - 1]
    def projStatus(i):
        return ['准备阶段', '采购阶段', '执行阶段'][int(i) -1]

    proj_data = {}
    proj_data['项目名'] = dt['projName'].strip()
    proj_data['发起时间'] = dt['startTime'].strip()
    proj_data['所在省'] = dt['distProvinceName'].strip()
    proj_data['所在市'] = dt['distCityName'].strip()
    proj_data['所在县'] = dt['distName'].strip()
    proj_data['项目总投资'] = dt['investCount']
    proj_data['回报机制'] = returnMode(dt['returnMode']).strip()
    proj_data['项目概况'] = dt['projSurvey'].strip()
    proj_data['运作方式'] = operateMode(dt['operateMode']).strip()
    proj_data['所属行业'] = dt['industryRequiredName'] + '-' + dt['industryOptionalName']
    proj_data['所处阶段'] = projStatus(dt['projStatus'])
    drop = []
    for k,v  in proj_data.items():
        if not v:
            drop.append(k)
            continue
        cursor.execute('select * from ppp limit 1')
        columns = set([x[0] for x in cursor.description])
        if k not in columns:
            cursor.execute(f'alter table ppp add {k} TEXT')
            db.commit()
    for i in drop:
        proj_data.pop(i)
    k = ','.join(proj_data.keys())
    print(proj_data)
    v = ','.join(['\'' + str(proj_data[k]) + '\'' for k in proj_data.keys()])
    print(f'insert into ppp ({k}) values ({v})')
    cursor.execute(f'insert into ppp ({k}) values ({v})')
    db.commit()
    
    # 运营模式在operateMode里面
    # yunzuofangshiurl = 'https://www.cpppc.org:8082/api/pub/project/query/enums/1004,1005,1048'
    # r = requests.get(yunzuofangshiurl, headers = headers)
    # print(r.text)
    
    

ppp()
# get_single_project()

爬取过程

首先进入数据库官网:https://www.cpppc.org:8082/inforpublic/homepage.html#/projectList
如果直接使用request.get方法来爬这个页面的数据,会发现爬不下来想要的数据,基本都是js的代码。那么就需要找到页面上面的数据是从哪里来的。在chrome浏览器中,按f12开启检查模式(或者在页面上面右键,然后检查)。点击network,然后刷新页面就可以看到显示这个页面时向服务器请求了什么数据。
在这里插入图片描述
可以看到,一次请求服务器会返回一个html,一堆js,还有一些图片。有两个0的文件不知道是什么,但是又一个search-store看上去比较可以,打开看一看里面是什么东西。
在这里插入图片描述
在preview中可以看到,貌似这个页面返回的就是所有的项目了(只有头5个,怎么翻页后面再说)。那怎么拿到这个返回值的呢?看一看headers里面有什么东西。
在这里插入图片描述
可以看到这个请求的链接并不是官网的链接,怪不得直接request官网得不到想要的数据,而且可以看到想得到这个信息,请求使用的是post而不是get。那关键字什么的在哪里加上去呢?看看request headers
在这里插入图片描述
request headers里面都是比较常规的东西,没什么需要注意的,需要注意的是request payload,看到里面有一个pageNumber,貌似找到从哪里来进行翻页了。然后有个问题就是我们想要找关键字怎么找呢?再在搜索框中输入医疗,然后搜索,发现返回了一个新的search-store,里面name变成了“医疗”。然后现在在主页面需要的信息就找全了。
在这里插入图片描述
注意到每个项目还可以点进去,那点进去之后的数据怎么爬呢?随便找一个项目点进去。
在这里插入图片描述
发现这个项目url有些编码看不懂。再多点几个项目,会发现最后一大串字符串是不一样的。那我们可以确定进入项目页面的方法就是url里面加上类似于项目id一类的东西。那项目id从哪里找呢?
我们把这个疗养院的“项目id”复制一下,在之前主页面返回的search-store的结果中搜索一下看看有没有发现
在这里插入图片描述
可以发现,主页面的返回结果是一个json,而proj_rid就是我们需要的项目id,拿到这个id和url拼接一下就可以找到每一个项目具体信息的链接了。
然后进入项目具体的链接,也发现直接request.get(项目url)是拿不到需要的信息的。那再用这个方法继续尝试。就可以找到返回值中每一个字段和页面中如何对应的。
在爬取项目具体信息的过程中,发现返回的json中没有bot之类的运作方式,那这个运作方式是在哪里呢?
在这里插入图片描述
在项目具体页面中,搜索bot,发现有4个文件包含bot,两个js不去管,看到一个叫做1004什么什么的文件比较可以,进去继续搜一下,发现果然找到了我们需要的内容,原来运作方式这个字段使用代码隐藏起来了。这个代码对应的是哪个字段呢?

在这里插入图片描述

如果直接搜dictcode,会发现有两个文件有这个东西,第二个js文件打开之后会发现并不是我们想要的东西。

在这里插入图片描述
一个一个翻阅文件,发现返回的这么多东西里面,有两个是我们感兴趣的。在第二个文件里面,有一个operatemode项
在这里插入图片描述
多检查几个就会发现这个operatemode就是我们想要的内容

发布了267 篇原创文章 · 获赞 12 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/u010734277/article/details/105685648
今日推荐