爬虫基础篇之多途径抓取失信人名单
需求
继爬虫基础篇之Scrapy抓取京东之后,我们对scrapy有了一定的掌握,接下来通过多渠道汇总对失信人信息抓取入库。
- 抓取百度失信人名单
- 抓取最高人民法院失信人名单
- 抓取国家企业信用公示系统失信人公告
- 把上面三个来源的失信人信息进行合并,去重
目标
百度
搜索失信人名单
抓取数据: 失信人名称, 失信人号码,法人(企业), 年龄(企业的年龄为0), 区域,失信内容, 公布日期, 公布执行单位, 创建日期, 更新日期
企业信用信息公示系统
- 访问http://www.gsxt.gov.cn/corp-query-entprise-info-xxgg-100000.html
- 抓取: 失信人名称, 失信人号码, 年龄(企业的年龄为0), 区域, 失信内容, 公布日期, 公布单位, 类型(个人/企业), 创建日期, 更新日期
实现
- 把抓取的数据, 统一存储到同一个数据库的, 同一张表中.
- 如何去重?
- 对于个人: 根据失信人号码, 检查一下, 如果不存在才插入.
- 对于企业/组织:
- 失信人证件号, 有的是组织机构代码, 有的是信用号, 企业信用信息公示系统的失信人公告有的没有证件号, 所以无法进行准确判断.
- 区域 和 企业名称进行检查, 如果有就重复了, 没有才插入.
百度
scrapy startproject dishonest
创建爬虫项目
数据模型
定义数据模型继承自scrapy.Item的数据模型DishonestItem
class DishonestItem(scrapy.Item):# define the fields for your item here like:# 失信人名称name = scrapy.Field()# 失信人证件号card_num = scrapy.Field()# 失信人年龄, 企业年龄都是0age = scrapy.Field()# 区域area = scrapy.Field()# 法人(企业)business_entity = scrapy.Field()# 失信内容content = scrapy.Field()# 公布日期publish_date = scrapy.Field()# 公布/执行单位publish_unit = scrapy.Field()# 创建日期create_date = scrapy.Field()# 更新日期update_date = scrapy.Field()
分析
通过翻页发起请求,在控制台的All请求下出现了https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?resource_id=6899&query=失信人名单&pn=0&ie=utf-8&oe=utf-8&format=json
的目标地址
参数:
- resource_id=6899: 资源id, 固定值
- query=失信人名单: 查询内容, 固定值
- pn=0: 数据起始号码
- ie=utf-8&oe=utf-8: 指定数据的编码方式, 固定值
- format=json: 数据格式, 固定值
我们可以根据第一次请求, 获取到总的数据条数, 生成所有页面的URL.
demo
url = 'https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?resource_id=6899&query=失信人&pn=10&rn=10&ie=utf-8&oe=utf-8'
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36','Referer': 'https://www.baidu.com/s?ie=UTF-8&wd=%E5%A4%B1%E4%BF%A1%E4%BA%BA'
}response = requests.get(url, headers=headers)
print(response.status_code)
print(response.content.decode())
爬虫实现
- 设置默认请求头, 在
settings.py
文件中
DEFAULT_REQUEST_HEADERS = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36','Referer': 'https://www.baidu.com/s?ie=UTF-8&wd=%E5%A4%B1%E4%BF%A1%E4%BA%BA'
}
scrapy genspider baidu baidu.com
创建爬虫- 分页实现
class BaiduSpider(scrapy.Spider):name = 'baidu'allowed_domains = ['baidu.com']start_urls = ['https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?resource_id=6899&query=失信人&pn=0&rn=10&ie=utf-8&oe=utf-8']def parse(self, response):# 构建所有页面请求# 把响应内容的json字符串, 转为字典results = json.loads(response.text)# 取出总数据条数disp_num = jsonpath(results, '$..dispNum')[0]# print(disp_num)# URL模板url_pattern = 'https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?resource_id=6899&query=失信人&pn={}&rn=10&ie=utf-8&oe=utf-8'# 每隔10条数据, 构建一个请求for pn in range(0, disp_num, 10):# 构建URLurl = url_pattern.format(pn)# 创建请求, 交给引擎yield scrapy.Request(url, callback=self.parse_data)def parse_data(self, response):"""解析数据"""# 响应数据datas = json.loads(response.text)results = jsonpath(datas, '$..result')[0]# 遍历结果列表for result in results:item = DishonestItem()# 失信人名称item['name'] = result['iname']# 失信人号码item['card_num'] = result['cardNum']# 失信人年龄item['age'] = int(result['age'])# 区域item['area'] = result['areaName']# 法人(企业)item['business_entity'] = result['businessEntity']# 失信内容item['content'] = result['duty']# 公布日期item['publish_date'] = result['publishDate']# 公布/执行单位item['publish_unit'] = result['courtName']# 创建日期item['create_date'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')# 更新日期item['update_date'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')# print(item)# 把数据交给引擎yield item
数据存储
- 创建数据库表
-- 创建数据库create database dishonest;-- 如果表存在就删除drop table if exists dishonest;-- 创建表create table dishonest(dishonest_id INT NOT NULL AUTO_INCREMENT, -- id主键age INT NOT NULL, -- 年龄, 自然人年龄都是>0的, 企业的年龄等于0name VARCHAR(200) NOT NULL, -- 失信人名称card_num VARCHAR(50) , -- 失信人号码area VARCHAR(50) NOT NULL, -- 区域content VARCHAR(2000) NOT NULL, -- 失信内容business_entity VARCHAR(20), -- 企业法人publish_unit VARCHAR(200), -- 发布单位publish_date VARCHAR(20), -- 发布单位create_date DATETIME, -- 创建日期update_date DATETIME, -- 更新日期PRIMARY KEY (dishonest_id));
- 在settings中配置数据库信息
# 配置MYSQL
# MYSQL的主机IP地址
MYSQL_HOST = '127.0.0.1'
# MYSQL端口号
MYSQL_PORT = 3306
# MYSQL用户名
MYSQL_USER = 'root'
# MYSQL密码
MYSQL_PASSWORD = ''
# MYSQL数据库名
MYSQL_DB = 'dishonest'
- 使用pipeline存储数据到mysql
class DishonestListPipeline(object):def open_spider(self, spider):# 创建数据链接self.connect = pymysql.connect(host="127.0.0.1",user="root", password="123",db="dishonest",port=3306)# 获取执行SQL的cursorself.cursor = self.connect.cursor()def close_spider(self, spider):# 释放游标self.cursor.close()# 释放链接self.connect.close()def process_item(self, item, spider):if item['age'] == 0:# 如果年龄 == 0 , 就是企业, 就根据公司名和区域进行查询name = item['name']area_name = item['area']select_sql = "select count(1) from t_dishonest where name='{}' and area = '{}'".format(name, area)else:# 如果是个人根据证件号, 数据条数select_sql = "select count(1) from t_dishonest where card_num='{}'".format(item['card_num'] )# 根据证件号, 数据条数select_sql = "select count(1) from dishonest where card_num='{}'".format(item['card_num'])# 执行查询SQLself.cursor.execute(select_sql)# 获取查询结果count = self.cursor.fetchone()[0]# 如果查询的数量为0, 说明该人不存在, 不存在就插入if count == 0:# 获取当前的时间, 为插入数据库的时间item['create_date'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')item['update_date'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')# 把数据转换为键, 值的格式, 方便插入数据库keys, values = zip(*dict(item).items())# 插入数据库SQLinsert_sql = 'insert into dishonest ({}) values({})'.format(','.join(keys),','.join(['%s'] * len(values)))# 执行插入数据SQLself.cursor.execute(insert_sql, values)# 提交self.connect.commit()else:spider.logger.info('{} 重复'.format(item))return itemif __name__ == '__main__':pipeline = DishonestListPipeline()pipeline.open_spider('xx')item = {'card_num': '12345'}pipeline.process_item(item, '')
随机User-Agent反反爬
- 在settings.py中添加USER_AGENTS列表
USER_AGENTS = ["Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)","Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)","Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)","Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)","Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)","Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)","Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)","Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6","Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1","Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0","Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5","Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20","Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER","Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 LBBROWSER","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)","Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)","Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1","Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5","Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre","Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11","Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10"
]
- 实现随机User-Agent下载器中间件
class RandomUserAgent(object):def process_request(self, request, spider):# 如果spider是公示系统爬虫, 就直接跳过if isinstance(spider, GsxtSpider):return None# 3. 实现process_request方法, 设置随机的User-Agentrequest.headers['User-Agent'] = random.choice(USER_AGENTS)return None
- settings.py中开启中间件
# 开启下载器中间件
DOWNLOADER_MIDDLEWARES = {'dishonest.dishonest.middlewares.RandomUserAgent': 543,
}
代理IP反反爬
实现代理IP下载器中间件,在settings.py中开启, 并配置重试次数,继爬虫基础篇之IP代理池实现的动态IP代理池启动用于本次失信人抓取。
class ProxyMiddleware(object):def process_request(self, request, spider):# 实现process_request方法, 设置代理IP# 如果spider是公示系统爬虫, 就直接跳过if isinstance(spider, GsxtSpider):return None# 1. 获取协议头protocol = request.url.split('://')[0]# 2. 构建代理IP请求的URLproxy_url = 'http://localhost:16888/random?protocol={}'.format(protocol)# 3. 发送请求, 获取代理IPresponse = requests.get(proxy_url)# 4. 把代理IP设置给request.meta['proxy']request.meta['proxy'] = response.content.decode()return None
配置代理池中间件及重试次数(毕竟免费ip不稳定)
# 开启下载器中间件
DOWNLOADER_MIDDLEWARES = {'dishonest.dishonest.middlewares.ProxyMiddleware': 500,'dishonest.dishonest.middlewares.RandomUserAgent': 543,
}
# 配置重试次数, 当使用不稳定代理的时候,可能会导致请求失败
RETRY_TIMES = 6
国家企业信用公示系统
继JS逆向之国家企业信用信息公示系统Cookie传递完成了cookie的逆向分析,本文利用Cookie的实现逻辑,在scrapy中实现公示系统的爬虫入库。
scrapy genspider gsxt gsxt.gov.cn
创建爬虫
准备起始URL, 打印响应内容
class GsxtSpider(scrapy.Spider):name = 'gsxt'allowed_domains = ['gsxt.gov.cn']# 准备起始start_urls = ['http://www.gsxt.gov.cn/corp-query-entprise-info-xxgg-100000.html']def parse(self, response):# 打印状态吗print(response.status)# 内容print(response.text)
修改原来的随机User-Agent, 和随机代理的下载器中间件类, 如果是公示系统
爬虫直接跳过.
# 随机User-Agent下载器中间件
class RandomUserAgent(object):def process_request(self, request, spider):# 国家企业信用信息系统爬虫, 每次发送请求必须携带cookie信息if isinstance(spider, GsxtSpider):return...# 代理下载器中间件
class ProxyMiddleware(object):def process_request(self, request, spider):# 发送请求获取代理IP# 如果是国家企业信用信息系统爬虫, 直接返回 if isinstance(spider, GsxtSpider):return
定制cookie
为了实现代理IP, User-Agent, cookie信息生成, 绑定和重用,实现步骤如下:
步骤
:- 实现生成cookie的脚本
- 用于生成多套代理IP, User-Agent, Cookie信息, 放到Redis
- 实现公示系统中间件类,
- 实现
process_request
方法, 从Redis中随机取出Cookie来使用, 关闭页面重定向. - 实现
process_response
方法, 如果响应码不是200 或 没有内容重试 - 在setting.py文件件中配置, 开启该下载器中间
- 实现
- 实现生成cookie的脚本
实现生成cookie的脚本
- 创建
gen_gsxt_cookies.py
文件, 在其中创建GenGsxtCookie
的类 - 实现一个方法, 用于把一套代理IP, User-Agent, Cookie绑定在一起的信息放到Redis的list中
- 随机获取一个User-Agent
- 随机获取一个代理IP
- 获取request的session对象
- 把User-Agent, 通过请求头, 设置给session对象
- 把代理IP, 通过proxies, 设置给session对象
- 使用session对象, 发送请求, 获取需要的cookie信息
- 把代理IP, User-Agent, Cookie放到字典中, 序列化后, 存储到Redis的list中
- 实现一个run方法, 用于开启多个异步来执行这个方法.
注
: 为了和下载器中间件交互方便, 需要在settings.py中配置一些常量.
- 创建
def push_cookie_to_redis(self):while True:try:"""2. 实现一个方法, 用于把一套代理IP, User-Agent, Cookie绑定在一起的信息放到Redis的list中"""# 1. 随机获取一个User-Agentuser_agent = random.choice(USER_AGENTS)# 2. 随机获取一个代理IP# response = requests.get('http://localhost:16888/random?protocol=http')# proxy = response.content.decode()# 3. 获取requests的session对象session = requests.session()# 4. 把User-Agent, 通过请求头, 设置给session对象session.headers = {'User-Agent': user_agent}# 5. 把代理IP, 通过proxies, 设置给session对象# session.proxies = {# 'http': proxy# }# 6. 使用session对象, 发送请求, 获取需要的cookie信息index_url = 'http://www.gsxt.gov.cn/corp-query-entprise-info-xxgg-100000.html'# 获取request的session对象, 可以自动合并cookie信息# ######################################################使用session发送index_url请求###########################response = session.get(index_url)print(response.status_code)# 第一次请求521 服务器借助这个请求设置一个Set-Cookie: __jsluid_h=8af7a39f7cdb1c46f8f624c972968c8f; max-age=31536000; path=/; HttpOnly到本地,并返回一段js########################################################拿到第一个cookie######################### 1. 提取script标签中的jsjs1 = re.findall('<script>(.+?)</script>', response.content.decode())[0].replace('document.cookie=','').replace('location.href=location.pathname+location.search', '')context = js2py.EvalJs()###################################################根据第一个请求返回的js生成第二个cookie###############################context.execute('cookies2 =' + js1)cookies = context.cookies2.split(';')[0].split('=')session.cookies.set(cookies[0], cookies[1]) # 到此拿到第两个cookie######################################################拿到第二个cookie############################# 第二次请求携带Cookie: __jsluid_h=6ed2648e0a734bc66e3011d648f6f1ab; __jsl_clearance=1619152879.013|-1|aS3lFknWlGtD%2FADiygf7vxl4yqk%3D返回一段js# 添加jsdom实现浏览器上下文js2 = '''const jsdom = require("jsdom");const {JSDOM} = jsdom;const dom = new JSDOM();window = dom.window;document = window.document;location = new Array();''' + \re.findall('<script>(.+?)</script>', session.get(index_url).content.decode('utf-8'))[0]# 正则获取document['cookie'],由于每次个数不一样我们取最后一个cookies2_1 = re.findall(r"document\[.*?\]=(.*?)location", js2, re.S)[-1]# 将document['cookie']内容返回给go函数js3 = re.sub("};go", "return " + cookies2_1 + "};go", js2, 1)# 获取调用go函数时里面的参数request = re.findall(r"go\({(.*?)}\)", js3, re.S)[-1]# 通过python修改js生成一个request方法final_js = js3 + "\nfunction request() {return go({" + request + "})}"# js调用request方法返回cookie并将新的__jsl_clearance塞给session中cookies3 = execjs.compile(final_js).call('request').split(';')[0].split('=')session.cookies.set(cookies3[0], cookies3[1])# 第三次请求 修改了__jsl_clearance后服务端向客户端设置新cookie的SECTOKENsession.get(index_url)cookies = requests.utils.dict_from_cookiejar(session.cookies)# print(cookies)# 7. 把代理IP, User-Agent, Cookie放到字典中, 序列化后, 存储到Redis的list中cookies_dict = {COOKIES_KEY:cookies,COOKIES_USER_AGENT_KEY:user_agent,# COOKIES_PROXY_KEY:proxy}# 序列化后, 存储到Redis的list中self.redis.lpush(REDIS_COOKIES_KEY, pickle.dumps(cookies_dict))print(cookies_dict)breakexcept Exception as ex:print("error",ex)
settings.py
中配置信息
# 定义cookie的键COOKIE_KEY = 'COOKIE' # 字典中Cookie键COOKIE_PROXY_KEY = 'COOKIE_PROXY' # 字典中代理IP的键COOKIE_USER_AGENT_KEY = 'COOKIE_USER_AGENT' # 字典中User-Agent的键REDIS_COOKIES_KEY = 'REDIS_COOKIES' # Redis的cookie列表的键REDIS_URL = 'redis://127.0.0.1:6379/0' # Redis数据库的链接
定制中间件
步骤
- 实现process_request方法, 从Redis中随机取出Cookie来使用, 关闭页面重定向.
- 实现process_response方法, 如果响应码不是200 或 没有内容重试
class GsxtCookieMiddleware(object):def __init__(self):"""建立Redis数据库连接"""self.redis = StrictRedis.from_url(REDIS_URL)def process_request(self, request, spider):"""从Redis中随机取出Cookie来使用, 关闭页面重定向."""count = self.redis.llen(REDIS_COOKIES_KEY)random_index = random.randint(0, count-1)cookie_data = self.redis.lindex(REDIS_COOKIES_KEY, random_index)# 反序列化, 把二进制转换为字典cookie_dict = pickle.loads(cookie_data)# 把cookie信息设置requestrequest.headers['User-Agent'] = cookie_dict[COOKIES_USER_AGENT_KEY]# 设置请求代理IPrequest.meta['proxy'] = cookie_dict[COOKIES_PROXY_KEY]# 设置cookie信息request.cookies = cookie_dict[COOKIES_KEY]# 设置不要重定向request.meta['dont_redirect'] = Truedef process_response(self, request, response, spider):"""如果响应码不是200 或 没有内容重试"""# print(response.status)if response.status != 200 or response.body == b'':# 备份请求req = request.copy()# 设置请求不过滤req.dont_filter = True# 把请求交给引擎return reqreturn response
在setting.py文件件中配置中间件
DOWNLOADER_MIDDLEWARES = {'dishonest.dishonest.middlewares.GsxtCookieMiddleware': 10,'dishonest.dishonest.middlewares.ProxyMiddleware': 500,'dishonest.dishonest.middlewares.RandomUserAgent': 543,
}
完善爬虫
- 解析页面中的城市名称和id, 构建公告信息的URL
- 解析失信企业公告信息
class GsxtSpider(scrapy.Spider):name = 'gsxt'allowed_domains = ['gsxt.gov.cn']# 准备起始start_urls = ['http://www.gsxt.gov.cn/corp-query-entprise-info-xxgg-100000.html']custom_settings = {'DOWNLOAD_DELAY' : 5}def parse(self, response):# 获取城市标签的div列表divs = response.xpath('//*[@id="qysx"]/div[3]/div')# 遍历divs, 获取城市id和名称for div in divs:area_id = div.xpath('./@id').extract_first()area_name = div.xpath('./label/text()').extract_first()# 准备请求的URLurl = 'http://www.gsxt.gov.cn/affiche-query-area-info-paperall.html?' \'noticeType=11&areaid=100000¬iceTitle=®Org={}'.format(area_id)# 一个城市最多能够获取50条数据.for i in range(0, 50, 10):data = {'start': str(i)}# 构建请求, 交给引擎yield scrapy.FormRequest(url, formdata=data, callback=self.parse_data,meta={'area_name': area_name})def parse_data(self, response):# print(response.text)"""解析页面中的城市"""area_name = response.meta['area_name']result = json.loads(response.text)datas = result['data']for data in datas:item = DishonestItem()# 区域名称item['area_name'] = area_name# 公告标题notice_title = data['noticeTitle']name = re.findall('关?于?(.+?)的?列入.*', notice_title)[0]item['name'] = name# 由于抓取的是失信企业公告, 所以抓到都是企业; 年龄设置为0item['age'] = 0notice_content = data['noticeContent']card_id = re.findall('经查.+[(\(]统一社会信用码/注册号:(\w+)[)\)]', notice_content)item['card_num'] = card_id[0] if len(card_id) != 0 else ''item['content'] = notice_content# 公布单位item['publish_unit'] = data['judAuth_CN']# 获取到的时间, 是1970年1月1日 0时0分0秒 到发布时间的毫秒数publish_ms = data['noticeDate']# 转换为日期类型publish_date = datetime.fromtimestamp(publish_ms / 1000)item['publish_date'] = publish_date.strftime('%Y年%m月%d日')yield item
爬虫基础篇之多途径抓取失信人名单相关推荐
- python爬虫基础之AJAX页面的抓取
一.基于AJAX请求页面的爬取 爬取网页:http://www.jy.whzbtb.com/V2PRTS 通过抓包,我们不难发现这是一个AJAX请求,我们需要携带必要的参数才能获取每一页的页面内容,具 ...
- Python爬虫之XPath基础教程:用代码抓取网页数据
Python爬虫之XPath基础教程:用代码抓取网页数据 在网络时代,网页数据是获取信息和进行分析的最重要的来源之一.Python的爬虫技术让我们可以轻松抓取网页数据,并进行数据处理.XPath是一种 ...
- python爬取新浪微博数据中心_Python爬虫框架Scrapy实战之批量抓取招聘信息
网络爬虫抓取特定网站网页的html数据,但是一个网站有上千上万条数据,我们不可能知道网站网页的url地址,所以,要有个技巧去抓取网站的所有html页面.Scrapy是纯Python实现的爬虫框架,用户 ...
- python爬取二级页面_爬虫代码改进(二)|多页抓取与二级页面
本文是下面两篇文章的续篇 本系列包括如下内容抓取豆瓣top250一页多个字段 整合成列表 存储为json文件 定义成函数形式 多页抓取之构造url 多页抓取之翻页 抓取二级页面数据 通过生成器优化代码 ...
- Python基础之12306车票信息抓取案例
Python基础之12306车票信息抓取案例 注:12306上请求网址链接经常变化,需要随时检查更改(我已经修改三遍了),请求的数据也有小几率发生变动,所以也需要检查更改 2018-10-22 第四遍 ...
- 爬虫练习(二)—股票信息抓取
爬虫练习(二)-股票信息抓取 1 思路 1.首先需要找到一个将股票信息存放在html上的股票网站 2.因为每一个股票都是一个独立的页面,所以在抓取时,首先要了解每个股票网址的规律(网址最后结尾都是股票 ...
- python爬取app播放的视频,Python爬虫工程师必学——App数据抓取实战视频教程
爬虫分为几大方向,WEB网页数据抓取.APP数据抓取.软件系统数据抓取.本课程主要为同学讲解如何用python实现App数据抓取,课程从开发环境搭建,App爬虫必备利器详解,项目实战,到最后的多App ...
- Python爬虫 | 斗图网表情包抓取
Python爬虫 | 斗图网表情包抓取 1.数据来源分析 2.制作div_list 3.发起请求 4.保存图片 5.批量获取 6.完整代码 声明 1.数据来源分析 打开斗图吧的主页,发现网址非常有 ...
- 爬虫实战:百度失信人名单
文章目录 失信人信息爬虫项目 1. 需求 2. 开发环境 3 抓取百度失信人名单 3.1. 实现步骤: 3.2 创建爬虫项目 3.3. 根据需求, 定义数据模型 3.4 实现百度失信名单爬虫 3.5. ...
- 爬虫基础篇之Scrapy抓取京东
虚拟环境 同一台服务器上不同的项目可能依赖的包不同版本,新版本默认覆盖旧版本,可能导致其他项目无法运行,通过虚拟环境,完全隔离各个项目各个版本的依赖包,实现运行环境互不影响. virtualenv p ...
最新文章
- Python 之 Pandas (八)图像
- STM32 flash
- UA PHYS515A 电磁理论V 电磁波与辐射3 偏振
- Boost:双图bimap与property地图的测试程序
- python中的rstrip函数_Python strip() lstrip() rstrip() 函数 去除空格
- dasblog的安装
- 比0 冷1度c语言编程,关于DS18B20的C语言程序(精确度0.1度).doc
- 高等数学上-赵立军-北京大学出版社-题解-练习5.5
- cf1557 C. Moamen and XOR
- 网页版四则运算(未全部完成)
- leetcode题解538-把二叉搜索树转化为累加树
- 感觉自己应该重新读一次Javascript
- php使用adodb下载,ADODB的使用
- 爬取m3u8格式文件并下载ts文件转换为MP4文件
- 淘宝、京东、苏宁易购技术架构分析
- 流年依旧,只是散了曾经
- 计算机围棋涉及知识,围棋知识介绍
- Revit二次开发入门秘籍 01如何入门
- Office 365 共享链接直接进入编辑
- 微信小程序代码大于2M的一种解决方法
热门文章
- 【中级—,android开发入门pdf
- css3新单位vw、vh、vmin、vmax的使用详解
- NextCloud如何共享文件
- 博客怎么推广才能达到最佳优化效果
- sourceTree 添加 ssh key 方法
- 各种工具配置忽略证书
- 淘宝客淘宝联盟解析二合一链接获取优惠链接还原二合一,提取优惠信息
- Some Laws in IT
- Feign出现The bean ‘seckill.FeignClientSpecification‘, defined in null, could not be registered. A be
- 数字货币智能合约:分析以太坊信标链