需求

继爬虫基础篇之Scrapy抓取京东之后,我们对scrapy有了一定的掌握,接下来通过多渠道汇总对失信人信息抓取入库。

  1. 抓取百度失信人名单
  2. 抓取最高人民法院失信人名单
  3. 抓取国家企业信用公示系统失信人公告
  4. 把上面三个来源的失信人信息进行合并,去重

目标

百度

  • 搜索失信人名单

  • 抓取数据: 失信人名称, 失信人号码,法人(企业), 年龄(企业的年龄为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())

爬虫实现

  1. 设置默认请求头, 在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'
}
  1. scrapy genspider baidu baidu.com 创建爬虫
  2. 分页实现
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

数据存储

  1. 创建数据库表
   -- 创建数据库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));
  1. 在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'
  1. 使用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反反爬

  1. 在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"
]
  1. 实现随机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
  1. 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的脚本

    • 创建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&noticeTitle=&regOrg={}'.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

爬虫基础篇之多途径抓取失信人名单相关推荐

  1. python爬虫基础之AJAX页面的抓取

    一.基于AJAX请求页面的爬取 爬取网页:http://www.jy.whzbtb.com/V2PRTS 通过抓包,我们不难发现这是一个AJAX请求,我们需要携带必要的参数才能获取每一页的页面内容,具 ...

  2. Python爬虫之XPath基础教程:用代码抓取网页数据

    Python爬虫之XPath基础教程:用代码抓取网页数据 在网络时代,网页数据是获取信息和进行分析的最重要的来源之一.Python的爬虫技术让我们可以轻松抓取网页数据,并进行数据处理.XPath是一种 ...

  3. python爬取新浪微博数据中心_Python爬虫框架Scrapy实战之批量抓取招聘信息

    网络爬虫抓取特定网站网页的html数据,但是一个网站有上千上万条数据,我们不可能知道网站网页的url地址,所以,要有个技巧去抓取网站的所有html页面.Scrapy是纯Python实现的爬虫框架,用户 ...

  4. python爬取二级页面_爬虫代码改进(二)|多页抓取与二级页面

    本文是下面两篇文章的续篇 本系列包括如下内容抓取豆瓣top250一页多个字段 整合成列表 存储为json文件 定义成函数形式 多页抓取之构造url 多页抓取之翻页 抓取二级页面数据 通过生成器优化代码 ...

  5. Python基础之12306车票信息抓取案例

    Python基础之12306车票信息抓取案例 注:12306上请求网址链接经常变化,需要随时检查更改(我已经修改三遍了),请求的数据也有小几率发生变动,所以也需要检查更改 2018-10-22 第四遍 ...

  6. 爬虫练习(二)—股票信息抓取

    爬虫练习(二)-股票信息抓取 1 思路 1.首先需要找到一个将股票信息存放在html上的股票网站 2.因为每一个股票都是一个独立的页面,所以在抓取时,首先要了解每个股票网址的规律(网址最后结尾都是股票 ...

  7. python爬取app播放的视频,Python爬虫工程师必学——App数据抓取实战视频教程

    爬虫分为几大方向,WEB网页数据抓取.APP数据抓取.软件系统数据抓取.本课程主要为同学讲解如何用python实现App数据抓取,课程从开发环境搭建,App爬虫必备利器详解,项目实战,到最后的多App ...

  8. Python爬虫 | 斗图网表情包抓取

    Python爬虫 | 斗图网表情包抓取 1.数据来源分析 2.制作div_list 3.发起请求 4.保存图片 5.批量获取 6.完整代码 声明 1.数据来源分析   打开斗图吧的主页,发现网址非常有 ...

  9. 爬虫实战:百度失信人名单

    文章目录 失信人信息爬虫项目 1. 需求 2. 开发环境 3 抓取百度失信人名单 3.1. 实现步骤: 3.2 创建爬虫项目 3.3. 根据需求, 定义数据模型 3.4 实现百度失信名单爬虫 3.5. ...

  10. 爬虫基础篇之Scrapy抓取京东

    虚拟环境 同一台服务器上不同的项目可能依赖的包不同版本,新版本默认覆盖旧版本,可能导致其他项目无法运行,通过虚拟环境,完全隔离各个项目各个版本的依赖包,实现运行环境互不影响. virtualenv p ...

最新文章

  1. Python 之 Pandas (八)图像
  2. STM32 flash
  3. UA PHYS515A 电磁理论V 电磁波与辐射3 偏振
  4. Boost:双图bimap与property地图的测试程序
  5. python中的rstrip函数_Python strip() lstrip() rstrip() 函数 去除空格
  6. dasblog的安装
  7. 比0 冷1度c语言编程,关于DS18B20的C语言程序(精确度0.1度).doc
  8. 高等数学上-赵立军-北京大学出版社-题解-练习5.5
  9. cf1557 C. Moamen and XOR
  10. 网页版四则运算(未全部完成)
  11. leetcode题解538-把二叉搜索树转化为累加树
  12. 感觉自己应该重新读一次Javascript
  13. php使用adodb下载,ADODB的使用
  14. 爬取m3u8格式文件并下载ts文件转换为MP4文件
  15. 淘宝、京东、苏宁易购技术架构分析
  16. 流年依旧,只是散了曾经
  17. 计算机围棋涉及知识,围棋知识介绍
  18. Revit二次开发入门秘籍 01如何入门
  19. Office 365 共享链接直接进入编辑
  20. 微信小程序代码大于2M的一种解决方法

热门文章

  1. 【中级—,android开发入门pdf
  2. css3新单位vw、vh、vmin、vmax的使用详解
  3. NextCloud如何共享文件
  4. 博客怎么推广才能达到最佳优化效果
  5. sourceTree 添加 ssh key 方法
  6. 各种工具配置忽略证书
  7. 淘宝客淘宝联盟解析二合一链接获取优惠链接还原二合一,提取优惠信息
  8. Some Laws in IT
  9. Feign出现The bean ‘seckill.FeignClientSpecification‘, defined in null, could not be registered. A be
  10. 数字货币智能合约:分析以太坊信标链