python爬虫爬取国家科技报告服务系统数据,共计30余万条 ...

十念  金牌会员 | 2022-9-24 15:10:53 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 792|帖子 792|积分 2376

python爬虫爬取国家科技报告服务系统数据,共计30余万条

按学科分类【中图分类】
共计三十余万条科技报告数据
爬取的网址:https://www.nstrs.cn/kjbg/navigation

!!!
如果要完整地跑起来代码,需要先看一下我的这篇博客,完成IP代理池的相关配置:
https://www.cnblogs.com/rainbow-1/p/16725503.html
!!!
分析网站数据来源可以发现,是使用的post方式的请求,且参数列表如下:


那么我们需要做的就是模拟这个请求,同时需要带上我们自定义的参数,这里面需要的其实一个就是页码pageNo,另一个是分类,如下图:
  1. parms = {
  2.             "pageNo": i,
  3.             "competentOrg": "",
  4.             "jihuaId": "",
  5.             "fieldCode": "",
  6.             "classification": name,   # 修改
  7.             "kjbgRegion": "",
  8.             "kjbgType": "",
  9.             "grade": ""
  10.         }
  11.         
复制代码
简单说一下我都做了什么,首先是配置是IP代理池,存在redis数据库,每次【设置了随机延迟时间】随机取出一个进行访问。
其次使用了随机UserAgent请求头。
爬虫是直接使用post请求,携带参数抓获返回的json数据做解析并存入mysql数据库。
下面是代码:
爬虫方法report_crawler

也就是你需要直接运行的方法。
我这部分是从"社会科学总论"这个分类开始爬的,前面那些如果需要爬,就直接改pageList页码列表、nameList名称列表、tableList数据库表列表就可以【切记是一 一对应的!】
  1. import jsonimport randomfrom time import sleepimport requestsfrom fake_useragent import UserAgentfrom report_data.into_mysql import insert_mysqlfrom report_data.ip_redis import my_redis"""post方法参数params:字典或字节序列,作为参数增加到链接中data:字典,字节序列或文件对象,作为请求的内容json:JSON格式的数据,作为Request的内容headers:字典,HTTP定制头(模拟浏览器进行访问)cookies:字典或CpplieJar,Request中的cookieauth:元祖,支持HTTP认证功能files:字典类型,传输文件timeout:设定超时时间,秒为单位proxies:字典类型,设定访问代理服务器,可以增加登陆认证allow_redirects:True//False,默认为True,重定向开关stream:True/False,默认为True,获取内容立即下载开关verify:True/False,默认为True,认证SSL证书开关cert:本地SSL证书路径"""# 页码pageList# 分类名称参数列表 nameList#def get_report(page,name,tableName):    # ------------------------------ 修改页码    for i in range(1,page):        print("---------------------------------")        ua = UserAgent()        print("【随机 UserAgent:】" + ua.random)  # 随机产生headers        temp_headers = ua.random        # --------------------------------------        test_redis = my_redis()        temp_proxy = test_redis.get_ip()        print("【随机 IP:】" + temp_proxy)        url="https://www.nstrs.cn/rest/kjbg/wfKjbg/list"        # url2 = "https://www.nstrs.cn/rest/kjbg/wfKjbg/list?pageNo=2&competentOrg=&jihuaId=&fieldCode=&classification=医药、卫生&kjbgRegion=&kjbgType=&grade="        parms = {
  2.             "pageNo": i,
  3.             "competentOrg": "",
  4.             "jihuaId": "",
  5.             "fieldCode": "",
  6.             "classification": name,   # 修改
  7.             "kjbgRegion": "",
  8.             "kjbgType": "",
  9.             "grade": ""
  10.         }
  11.         other_parms={                'User-Agent': temp_headers,                'https': 'http://'+temp_proxy,                'http': 'http://'+temp_proxy            }        sleeptime = random.uniform(0, 0.7)        sleep(sleeptime)        # print(url)        response = requests.post(url, parms, other_parms)        response.encoding='utf8'        print(response.text+'\n')        response_data = response.text   # 返回数据        json_data = json.loads(response_data)   # 封装字典        res_list_data = json_data['RESULT']['list']   # 一页 长度为10的list [{ },{ },{ } ... { }] len=10        """        重新构建一个 list [{ }]        """        for item in res_list_data:            insert_mysql(item,name,tableName)    returnif __name__ == '__main__':    # 页码 pageList []    pageList = [788,779,656,584,573,510,440,361,                315,226,224,220,155,112,112,                87,53,50,39,33,18,12,5,4,2,2,2,2]    nameList = [        "社会科学总论",        "环境科学、安全科学",        "建筑科学",        "轻工业、手工业",        "数理科学与化学",        "能源与动力工程",        "电工技术",        "矿业工程",        "经济",        "文化、科学、教育、体育",        "水利工程",        "交通运输",        "自然科学总论",        "石油、天然气工业",        "冶金工业",        "武器工业",        "航空、航天",        "哲学、宗教",        "原子能技术",        "历史、地理",        "政治、法律",        "艺术",        "语言、文字",        "军事",        "综合性图书",        "文学",        "语言、文学",        "mks主义、ln主义、mzd思想、dxp理论"    ]    tableList = ["tech_c","tech_x","tech_tu","tech_ts","tech_o","tech_tk","tech_tm",                 "tech_td","tech_f","tech_g","tech_tv","tech_u",                 "tech_n","tech_te","tech_tf","tech_tj","tech_v","tech_b","tech_tl",                 "tech_k","tech_d","tech_j","tech_h","tech_e","tech_z","tech_i","tech_i","tech_a"]    for i in range(0,len(tableList)):        get_report(pageList[i],nameList[i],tableList[i])
复制代码
目录方法category

返回一个中图分类号对应的名称
  1. # 用以返回中图分类号
  2. def get_code(key):
  3.     code_dict = {
  4.         "医药、卫生":"R",
  5.         "一般工业技术":"TB",
  6.         "生物科学":"Q",
  7.         "数理科学和化学":"O",
  8.         "农业科学":"S",
  9.         "工业技术":"T",
  10.         "自动化技术、计算机技术":"TP",
  11.         "天文学、地球科学":"P",
  12.         "无线电电子学、电信技术":"TN",
  13.         "金属学与金属工艺":"TG",
  14.         "机械、仪表工业":"TH",
  15.         "化学工业":"TQ",
  16.         "社会科学总论":"C",
  17.         "环境科学、安全科学":"X",
  18.         "建筑科学":"TU",
  19.         "轻工业、手工业":"TS",
  20.         "数理科学与化学":"O",
  21.         "能源与动力工程":"TK",
  22.         "电工技术":"TM",
  23.         "矿业工程":"TD",
  24.         "经济":"F",
  25.         "文化、科学、教育、体育":"G",
  26.         "水利工程":"TV",
  27.         "交通运输":"U",
  28.         "自然科学总论":"N",
  29.         "石油、天然气工业":"TE",
  30.         "冶金工业":"TF",
  31.         "武器工业":"TJ",
  32.         "航空、航天":"V",
  33.         "哲学、宗教":"B",
  34.         "原子能技术":"TL",
  35.         "历史、地理":"K",
  36.         "政治、法律":"D",
  37.         "艺术":"J",
  38.         "语言、文字":"H",
  39.         "军事":"E",
  40.         "综合性图书":"Z",
  41.         "文学":"I",
  42.         "语言、文学":"I",
  43.         "mks主义、ln主义、mzd思想、dxp理论":"A",
  44.     }
  45.     res = code_dict.get(key)
  46.     return res
  47. if __name__ == '__main__':
  48.     data = get_code("工业技术")
  49.     print(data)
复制代码

user_agent方法

返回随机headers
  1. from fake_useragent import UserAgent   # 下载:pip install fake-useragent
  2. import requests
  3. ua = UserAgent()        # 实例化,需要联网但是网站不太稳定-可能耗时会长一些
  4. print(ua.random)  # 随机产生
  5. headers = {
  6.     'User-Agent': ua.random    # 伪装
  7.     }
  8. # 请求
  9. if __name__ == '__main__':
  10.     url = 'https://www.baidu.com/'
  11.     response = requests.get(url, headers=headers ,proxies={"http":"117.136.27.43"})
  12.     print(response.status_code)
复制代码
ip_redis方法

从redis数据库取出一个ip并返回(前3000个随机一个,降序排列)
  1. import random
  2. import redis
  3. class my_redis:
  4.     def get_ip(self):
  5.         r = redis.Redis(host='127.0.0.1', port=6379, db=0,decode_responses=True)
  6.         my_redis_data = r.zrange("proxies:universal",1,3000,True)
  7.         return random.choice(my_redis_data)
  8.         # print(len(my_redis_data))
  9. if __name__ == '__main__':
  10.     test_redis=my_redis()
  11.     data=test_redis.get_ip()
  12.     print(data)
复制代码
into_mysql方法

存入mysql数据库的方法
  1. #连接数据库  获取游标
  2. import pymysql
  3. from report_data.category import get_code
  4. def get_conn():
  5.     """
  6.     :return: 连接,游标
  7.     """
  8.     # 创建连接
  9.     conn = pymysql.connect(host="127.0.0.1",
  10.                     user="root",
  11.                     password="reliable",
  12.                     db="tech",
  13.                     charset="utf8mb4")
  14.     # 创建游标
  15.     cursor = conn.cursor()  # 执行完毕返回的结果集默认以元组显示
  16.     if ((conn != None) & (cursor != None)):
  17.         print("数据库连接成功 ...")
  18.     else:
  19.         print("数据库连接失败!")
  20.     return conn, cursor
  21. #关闭数据库连接和游标
  22. def close_conn(conn, cursor):
  23.     if cursor:
  24.         cursor.close()
  25.     if conn:
  26.         conn.close()
  27.     return 1
  28. # 数据表名
  29. # 中图分类名
  30. def insert_mysql(data,name,tableName):
  31.     print(data['title'])
  32.     id=data['id']
  33.     title=data['title']
  34.     alternativeTitle=data['alternativeTitle']
  35.     creator=data['creator']
  36.     abstractEn=data['abstractEn']
  37.     keywordsEn=data['keywordsEn']
  38.     abstractCn=data['abstractCn']
  39.     keywordsCn=data['keywordsCn']
  40.     creatOrorganization=data['creatOrorganization']
  41.     prepareOrganization=data['prepareOrganization']
  42.     publicDate=data['publicDate']
  43.     createTime=data['createTime']
  44.     projectName=data['projectName']
  45.     competentOrg=data['competentOrg']
  46.     projectSubjectName=data['projectSubjectName']
  47.     projectSubjectId=data['projectSubjectId']
  48.     #------------------------------
  49.     classification=name   # 修改
  50.     #------------------------------
  51.     classificationCode=get_code(classification)   # 需要调用get_code(name)获取
  52.     responsiblePerson = data['responsiblePerson']
  53.     supportChannel = data['supportChannel']
  54.     undertakeOrg = data['undertakeOrg']
  55.     kjbgSource = data['kjbgSource']
  56.     proposalDate = data['proposalDate']
  57.     submittedDate = data['submittedDate']
  58.     kjbgRegion = data['kjbgRegion']
  59.     collectionDate = data['collectionDate']
  60.     collectionNumber = data['collectionNumber']
  61.     fieldCode = data['fieldCode']
  62.     fieldId = data['fieldId']
  63.     kjbgQWAddress = data['kjbgQWAddress']
  64.     isNewRecord = data['isNewRecord']
  65.     sourceUrl = "https://www.nstrs.cn/kjbg/detail?id="+id          # 需要自己拼 https://www.nstrs.cn/kjbg/detail?id=
  66.     conn, cursor = get_conn()
  67.     # ------------------------------ 修改表名
  68.     sql = "insert into `"+tableName+"` (id,title,alternativeTitle,creator,abstractEn," \
  69.           "keywordsEn,abstractCn,keywordsCn,creatOrorganization,prepareOrganization," \
  70.           "publicDate,createTime,projectName,competentOrg,projectSubjectName," \
  71.           "projectSubjectId,classification,classificationCode,responsiblePerson,supportChannel," \
  72.           "undertakeOrg,kjbgSource,proposalDate,submittedDate,kjbgRegion," \
  73.           "collectionDate,collectionNumber,fieldCode,fieldId,kjbgQWAddress," \
  74.           "isNewRecord,sourceUrl) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s" \
  75.           ",%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
  76.     try:
  77.         try:
  78.             cursor.execute(sql, [id,title,alternativeTitle,creator,abstractEn,
  79.                       keywordsEn,abstractCn,keywordsCn,creatOrorganization,prepareOrganization,
  80.                       publicDate,createTime,projectName,competentOrg,projectSubjectName,
  81.                       projectSubjectId,classification,classificationCode,responsiblePerson,supportChannel,
  82.                       undertakeOrg,kjbgSource,proposalDate,submittedDate,kjbgRegion,
  83.                       collectionDate,collectionNumber,fieldCode,fieldId,kjbgQWAddress,isNewRecord,sourceUrl])
  84.         except pymysql.err.IntegrityError:
  85.             print("主键冲突!")
  86.         conn.commit()  # 提交事务 update delete insert操作
  87.     except pymysql.err.IntegrityError:
  88.         print("error!")
  89.     finally:
  90.         close_conn(conn, cursor)
  91.     return 1
  92. if __name__ == '__main__':
  93.     print()
复制代码
最终爬取三十多万条科技报告,按中图分类建立了mysql数据表,分表存储不同分类的数据。
【其中的数理科学和化学,数理科学与化学这两个分类做了合并,合并为数理科学和化学类,属O】
【语言、文学和文学做了合并,同属 I 文学类】



附几张结果图:

最后说一下数据表结构:
  1. /*
  2. Navicat MySQL Data Transfer
  3. Source Server         : reliable
  4. Source Server Version : 80013
  5. Source Host           : localhost:3306
  6. Source Database       : tech
  7. Target Server Type    : MYSQL
  8. Target Server Version : 80013
  9. File Encoding         : 65001
  10. Date: 2022-09-24 13:54:05
  11. */
  12. SET FOREIGN_KEY_CHECKS=0;
  13. -- ----------------------------
  14. -- Table structure for tech_o
  15. -- ----------------------------
  16. DROP TABLE IF EXISTS `tech_o`;
  17. CREATE TABLE `tech_o` (
  18.   `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID',
  19.   `title` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '中文标题',
  20.   `alternativeTitle` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '英文标题',
  21.   `creator` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '作者',
  22.   `abstractEn` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '英文摘要',
  23.   `keywordsEn` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '英文关键字',
  24.   `abstractCn` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '中文摘要',
  25.   `keywordsCn` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '中文关键字',
  26.   `creatOrorganization` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '创建者组织',
  27.   `prepareOrganization` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '预备组织',
  28.   `publicDate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '公布时间',
  29.   `createTime` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '编制时间',
  30.   `projectName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '项目名称',
  31.   `competentOrg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '项目地址',
  32.   `projectSubjectName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '项目主题名称',
  33.   `projectSubjectId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '项目主题ID',
  34.   `classification` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '中图分类名称',
  35.   `classificationCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '中图分类号',
  36.   `responsiblePerson` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '负责人',
  37.   `supportChannel` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '主办方',
  38.   `undertakeOrg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '承办方',
  39.   `kjbgSource` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '科技报告来源单位',
  40.   `proposalDate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '提议时间',
  41.   `submittedDate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '提交时间',
  42.   `kjbgRegion` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '科技报告所属行政区划',
  43.   `collectionDate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收集时间',
  44.   `collectionNumber` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收集编号',
  45.   `fieldCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '领域代码',
  46.   `fieldId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '领域ID',
  47.   `kjbgQWAddress` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '报告链接',
  48.   `isNewRecord` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否新记录',
  49.   `sourceUrl` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '国家科技报告服务系统收录链接',
  50.   PRIMARY KEY (`id`)
  51. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码


如果需要获取这部分数据,可关注我的微信公众号【小杨的挨踢IT生活】,回复 “科技报告” 获取下载链接。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

十念

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表