写在前面
爬虫框架也是需要掌握的知识,这次尝试抓取药监局的化妆品信息,并保存到excel和MongoDB数据库中。
目标地址
准备工作
#创建scrapy项目
scrapy startproject NMPA
#进入项目目录
cd NMPA
#创建spider
scrapy genspider nmpaspider "scxk.nmpa.gov.cn"
修改items
import scrapy
class NmpaItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
epsName = scrapy.Field() #企业名称
productSn = scrapy.Field() #许可证编号
certStr = scrapy.Field() #许可项目
epsAddress = scrapy.Field() #企业住所
epsProductAddress = scrapy.Field() #生产地址
businessLicenseNumber = scrapy.Field() #社会信用代码
legalPerson = scrapy.Field() #法定代表人
businessPerson = scrapy.Field() #企业负责人
qualityPerson = scrapy.Field() #质量负责人
qfManagerName = scrapy.Field() #发证机关
xkName = scrapy.Field() #签发人
rcManagerDepartName = scrapy.Field() #日常监督管理机构
rcManagerUser = scrapy.Field() #日常监督管理人员
xkDate = scrapy.Field() #有效期至
xkDateStr = scrapy.Field() #发证日期
抓取模块
修改spiders目录下的nmpaspider.py文件
import scrapy
from NMPA.items import NmpaItem
class NmpaspiderSpider(scrapy.Spider):
#爬虫名称
name = 'nmpaspider'
#网页请求限定在此域名下
allowed_domains = ['scxk.nmpa.gov.cn']
#重写start_requests方法,循环抓取多页
def start_requests(self):
#向目标地址发起post请求
url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList'
#一共有362页
for i in range(1,363):
#page参数决定目标页
data = {
'on':'true',
'page':str(i),
'pageSize':'15',
'productNone':'',
'conditionType':'1',
'applyname':'',
'applysn':'',
}
#发起post请求,并将response传递给parse方法
yield scrapy.FormRequest(url = url, callback = self.parse,formdata = data)
def parse(self, response):
#获取当前页中的id,用于请求详细信息
id_lists = response.json()['list']
#详细信息的url
url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
#遍历每一个id
for id_ in id_lists:
#构造请求的参数
data = {'id':id_['ID']}
#发起post请求,并将response传递给get_details方法
yield scrapy.FormRequest(url = url,formdata = data,callback = self.get_details)
def get_details(self,response):
#创建item对象
item = NmpaItem()
#将response转换为json字典
details = response.json()
#为item对象赋值
item['epsName'] = details['epsName']
item['productSn'] = details['productSn']
item['certStr'] = details['certStr']
item['epsAddress'] = details['epsAddress']
item['epsProductAddress'] = details['epsProductAddress']
item['businessLicenseNumber'] = details['businessLicenseNumber']
item['legalPerson'] = details['legalPerson']
item['businessPerson'] = details['businessPerson']
item['qualityPerson'] = details['qualityPerson']
item['qfManagerName'] = details['qfManagerName']
item['xkName'] = details['xkName']
item['rcManagerDepartName'] = details['rcManagerDepartName']
item['rcManagerUser'] = details['rcManagerUser']
item['xkDate'] = details['xkDate']
item['xkDateStr'] = details['xkDateStr']
yield item
管道文件
pipelines.py
#操作MongoDB
import pymongo
#操作Excel
import openpyxl
#数据库索引及Excel表头
title_list = [
'企业名称', '许可证编号', '许可项目',
'企业住所', '生产地址', '社会信用代码', '法定代表人',
'企业负责人', '质量负责人', '发证机关','签发人',
'日常监督管理机构', '日常监督管理人员', '有效期至', '发证日期'
]
#这个类是创建的时候自带的
class NmpaPipeline:
def process_item(self, item, spider):
return item
#关于数据库的管道
class mongodbpipeline:
#初始化
def __init__(self):
#连接数据库,请替换user和passwd
self.client = pymongo.MongoClient('mongodb://user:passwd@localhost:27017')
#目标数据库,不存在则自动创建
self.db = self.client.nmpa
#目标table,不存在则自动创建
self.collection = self.db.data
def process_item(self,item,spider):
#创建一个空字典用于保存重构后的数据
dict_items = {}
#将item转换为字典格式
item = dict(item)
#重构数据,将字典中的键替换为中文
for k,v in zip(title_list,item.keys()):
dict_items[k] = item[v]
#在数据库中插入一条
self.collection.insert(dict_items)
#将item返回,执行下一管道
return item
#此方法只在管道执行完毕后运行一次,可以自定义输出信息
def close_spider(self,scrapy):
print('MongoDB执行完毕')
#关于Excel的管道
class openpyxlpipeline:
#初始化
def __init__(self):
#创建工作表
self.wb = openpyxl.Workbook()
#创建sheet
self.ws = self.wb.active
#插入索引
self.ws.append(title_list)
def process_item(self,item,spider):
#创建空列表用于保存一行信息
list_items = []
#将item转换为字典格式
item = dict(item)
#将字典的值保存到列表
for v in item.keys():
list_items.append(item[v])
#向表格中插入一行数据
self.ws.append(list_items)
#返回item以执行下一管道
return item
#在管道执行完毕后保存工作表
def close_spider(self,scrapy):
self.wb.save('nmpa.xlsx')
print('Openpyxl执行完毕')
修改配置
settings.py
#关闭robot检查
ROBOTSTXT_OBEY = False
#自定义延迟(发生在两个请求之间)
DOWNLOAD_DELAY = 0.25
#关闭cookie缓存
COOKIES_ENABLED = False
#开启中间件
DOWNLOADER_MIDDLEWARES = {
'NMPA.middlewares.NmpaDownloaderMiddleware': 543,
}
#管道执行的顺序,数字越小优先级越高,数字为0-1000
ITEM_PIPELINES = {
'NMPA.pipelines.mongodbpipeline': 300,
'NMPA.pipelines.openpyxlpipeline': 301,
}
伪造请求头
修改middlewares.py
from fake_useragent import UserAgent
#该方法位于NmpaDownloaderMiddleware类下
def process_request(self, request, spider):
ua = UserAgent().random
request.headers['User-Agent'] = ua
return None
运行爬虫
#普通运行(在NMPA目录下)
scrapy crawl nmpaspider
#禁用日志信息
scrapy crawl nmpaspider -s LOG_ENABLED=0
#将日志信息保存到log文件
scrapy crawl nmpaspider -s LOG_FILE=nmpa.log