目的:爬取信用中国(山西)中行政处罚和法人的详细信息,包括:行政处罚决定书文号、案件名称、处罚类型、处罚事由、处罚依据、......、数据报送时间
结果呈现:采用MySQL存储数据
注:这个简单的例子很经典,我花了很长时间分析网站,在“小耿童鞋”的指导下,我才知道要对函数进行分析,创建新的访问地址,才解决了问题!!!
注:爬取政府机构的网页,嗯......都是bug!很多都没有遇到过!嘻嘻,正好给我练手!!!
注:今天先将怎么分析网页的,后面在附上代码!
分析思路:
网址:http://www.creditsx.gov.cn/xzcfListNew.jspx
右击→查看网页源代码,发现:源代码中只有conpany-name(行政相对人名称)、company-message(数据送报时间)。
但是在该网址下,按F12在<div class="detail row">中存放着每个公司的“行政处罚详细信息”,所以详细数据是存在的,只是不知道它存放在哪了......
(1)自己的想法
查看资料,怀疑详细数据是存放在network下的.js格式的数据,但是根据博客内容【如何从json数据中爬取信息https://blog.csdn.net/weixin_36604953/article/details/78592943】,发现行政处罚的详细信息并不是存放在.js的文件中。(因为我自己分析了所有的.js文件,都没有我要的详细信息!)
(2)“小耿同学”点题
1)首先在该网页下,按F12,在整个数据块的末尾有个注释(见下图),其中:οnclick="page('2')"表示跳转到下一页,但是原网址最下面就没有“下一页”的选项!
2)右击→查看源代码,在最后发现函数:分页虚拟表单
- 其中action="/xzcfListNew.jspx" 是要访问的网址
- form.attr("method","POST"); 表示该网页是post请求访问,所以需要找到data参数
- input_pageNo.attr('value',pageNo); 输入的pageNo,所以data里面的参数就是pageNo
所以:访问的网址为:http://www.creditsx.gov.cn/xzcfListNew.jspx 访问方式是post,传入参数是pageNo,则可以爬取我们想要的内容!
【但是,这个网站做了限制,只能爬取1,2页,从第三页开始,就爬不到详细信息,返回的text是空的】
【第三页之后,<ul class="search-result-list">就不存在了】
所以就先完成第1页和第2页的爬取!
但是:其实还是爬取不到详细的信息,还是只有conpany-name(行政相对人名称)、company-message(数据送报时间)!
获取详细信息,查看网页源代码的后面有个infoDetail()函数:
输入:id (在上述的页面能够获得id,且每个案件对应不同的id),比如:
目的:找到行政处罚详细信息的url,根据官网的url(http://www.creditsx.gov.cn),构建爬取详细信息的url
比如:http://www.creditsx.gov.cn/xzcfDetialNew-da9e6978904346ceaa28edbabe29b5a0.jspx 找到行政处罚的详细信息,如下图:
PS:第3页之后的信息又被做了加密,我这边就不破解了,个人觉得没什么必要了。
(3)数据库入库
在MySQL中操作:
【进入mysql】
mysql> create database if not exists shanxi default charset utf8 collate utf8_general_ci; Query OK, 1 row affected, 1 warning (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | filmdb | | mysql | | performance_schema | | sakila | | shanxi | | taobao | | test123 | | txkg | | world | | zonghe_test | +--------------------+ mysql> use shanxi; Database changed mysql> create table info( -> id int(11) auto_increment, -> cfWsh varchar(255), -> cfCflb varchar(255), -> cfSy varchar(255), -> cfYj varchar(255), -> cfXdrMc varchar(255), -> cfXdrShxym varchar(255), -> cfXdrSfz varchar(255), -> cfFr varchar(255), -> cfXzjg varchar(255), -> cfSxq varchar(255), -> cfJg varchar(255), -> depName varchar(255), -> publishDate varchar(255), -> primary key(id)); Query OK, 0 rows affected (0.45 sec) mysql> describe info; +-------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | cfWsh | varchar(255) | YES | | NULL | | | cfCflb | varchar(255) | YES | | NULL | | | cfSy | varchar(255) | YES | | NULL | | | cfYj | varchar(255) | YES | | NULL | | | cfXdrMc | varchar(255) | YES | | NULL | | | cfXdrShxym | varchar(255) | YES | | NULL | | | cfXdrSfz | varchar(255) | YES | | NULL | | | cfFr | varchar(255) | YES | | NULL | | | cfXzjg | varchar(255) | YES | | NULL | | | cfSxq | varchar(255) | YES | | NULL | | | cfJg | varchar(255) | YES | | NULL | | | depName | varchar(255) | YES | | NULL | | | publishDate | varchar(255) | YES | | NULL | | +-------------+--------------+------+-----+---------+----------------+ 14 rows in set (0.03 sec)
#注:都采用varchar字符串的形式,这样比较方便。
之后直接在python中使用pymysql,将爬取的数据存入数据库中。
思路分析完毕!这个爬虫,我认为真的太经典了!!!这个思路要学会掌握!
(`・ω・´)(`・ω・´)(`・ω・´)(`・ω・´)(`・ω・´)(`・ω・´)(`・ω・´)(`・ω・´)
本爬虫代码:
行政惩罚的官网:http://www.creditsx.gov.cn/xzcfListNew.jspx
信用山西的官网:http://www.creditsx.gov.cn
#下面为本实例的爬虫代码,若有问题可以给我留言,或者有更好的解决方法也可以私信我~
注:访问带多次,ip又被限制了!不用怕,上次写的代理池,这次直接用上!(看ip代理池,请移步:https://my.oschina.net/pansy0425/blog/2990702)
#采用POST方式访问,参数传入data是pageNo,找到id,构造新的url,访问行政处罚的详细信息 import requests from bs4 import BeautifulSoup import json import pymysql import random def get_urllist(url): useful_ip_proxy = [] with open('useful_ip_proxy.txt', 'r')as f: info = f.readlines() for line in info: res = line.split('\n')[0] useful_ip_proxy.append(res) f.close() url_list=[] base_url='http://www.creditsx.gov.cn' for i in range(1,3): #只能爬取第1页和第2页 headers = {'user-agent': 'Mozilla/5.0'} data={'pageNo':str(i)} try: proxy = random.choice(useful_ip_proxy) proxies = { 'http': 'http://' + proxy, 'https': 'https://' + proxy } r=requests.post(url,data=data,headers=headers,proxies=proxies,timeout=5) r.raise_for_status() r.encoding=r.apparent_encoding html=r.text soup=BeautifulSoup(html,'html.parser') divs=soup.find_all('div',{'class':{"company-box"}}) for div in divs: id=div['id'] info_url=base_url+'/xzcfDetialNew-'+id+'.jspx' url_list.append(info_url) except: proxy = random.choice(useful_ip_proxy) proxies = { 'http': 'http://' + proxy, 'https': 'https://' + proxy } r = requests.post(url,data=data,headers=headers,proxies=proxies,timeout=5) r.raise_for_status() r.encoding = r.apparent_encoding html = r.text soup = BeautifulSoup(html, 'html.parser') divs = soup.find_all('div', {'class': {"company-box"}}) for div in divs: id = div['id'] info_url = base_url + '/xzcfDetialNew-' + id + '.jspx' url_list.append(info_url) return url_list def get_info(url): #获取行政处罚的详细信息 headers={'user-agent':'Mozilla/5.0'} try: r=requests.get(url,headers=headers) r.raise_for_status() data=json.loads(r.text) #转化为字典的格式 cfWsh=data['cfWsh'] #行政处罚决定书文号 cfCflb=data['cfCflb'] #处罚类别 cfSy=data['cfSy'] #处罚事由 cfYj=data['cfYj'] #处罚依据 cfXdrMc=data['cfXdrMc'] #行政相对人名称 cfXdrShxym=data['cfXdrShxym'] #统一社会信用代码 cfXdrSfz=data['cfXdrSfz'] #法定代表人居民身份证号 cfFr=data['cfFr'] #法定代表人姓名 cfXzjg=data['cfXzjg'] #处罚结果 cfSxq=data['cfSxq'] #处罚生效期 cfJg=data['cfJg'] #处罚机关 depName=data['depName'] #信息提供部门 publishDate=data['publishDate'] #数据送报时间时间 info=[cfWsh,cfCflb,cfSy,cfYj,cfXdrMc,cfXdrShxym,cfXdrSfz,cfFr,cfXzjg,cfSxq,cfJg,depName,publishDate] data_mysql(info) except Exception as e: print(e) def data_mysql(info): db=pymysql.connect(host='localhost',port=3306,user='root',passwd='12345678',db='shanxi',charset='utf8') cursor=db.cursor() sql="""insert into info(cfWsh,cfCflb,cfSy,cfYj,cfXdrMc,cfXdrShxym,cfXdrSfz,cfFr,cfXzjg,cfSxq,cfJg,depName,publishDate) values ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}')""".format(info[0],info[1],info[2],info[3],info[4],info[5],info[6],info[7],info[8],info[9],info[10],info[11],info[12]) try: cursor.execute(sql) db.commit() print('行政处罚决定书文号-{}-存入成功!'.format(info[0])) except: db.rollback() print('行政处罚决定书文号-{}-存入失败!'.format(info[0])) if __name__ == '__main__': start_url='http://www.creditsx.gov.cn/xzcfListNew.jspx' url_list=get_urllist(start_url) #得到每个详细的url 【每个的行政惩罚url】 print(url_list) for url in url_list: get_info(url)
(1)屏幕显示:
(2)MySQL中数据库显示:
爬取成功!
上次被小耿童鞋吐槽:你咋还用函数写代码?!要用面向对象!!!
好的,我再整合下!
面向对象代码如下:
#采用POST方式访问,参数传入data是pageNo,找到id,构造新的url,访问行政处罚的详细信息 import requests from bs4 import BeautifulSoup import json import pymysql import random class SX(): def __init__(self): pass def get_urllist(self,url): useful_ip_proxy = [] with open('useful_ip_proxy.txt', 'r')as f: info = f.readlines() for line in info: res = line.split('\n')[0] useful_ip_proxy.append(res) f.close() url_list=[] base_url='http://www.creditsx.gov.cn' for i in range(1,3): #只能爬取第1页和第2页 headers = {'user-agent': 'Mozilla/5.0'} data={'pageNo':str(i)} try: proxy = random.choice(useful_ip_proxy) proxies = { 'http': 'http://' + proxy, 'https': 'https://' + proxy } r=requests.post(url,data=data,headers=headers,proxies=proxies,timeout=5) r.raise_for_status() r.encoding=r.apparent_encoding html=r.text soup=BeautifulSoup(html,'html.parser') divs=soup.find_all('div',{'class':{"company-box"}}) for div in divs: id=div['id'] info_url=base_url+'/xzcfDetialNew-'+id+'.jspx' url_list.append(info_url) except: proxy = random.choice(useful_ip_proxy) proxies = { 'http': 'http://' + proxy, 'https': 'https://' + proxy } r = requests.post(url,data=data,headers=headers,proxies=proxies,timeout=5) r.raise_for_status() r.encoding = r.apparent_encoding html = r.text soup = BeautifulSoup(html, 'html.parser') divs = soup.find_all('div', {'class': {"company-box"}}) for div in divs: id = div['id'] info_url = base_url + '/xzcfDetialNew-' + id + '.jspx' url_list.append(info_url) return url_list def get_info(self,url): #获取行政处罚的详细信息 headers={'user-agent':'Mozilla/5.0'} try: r=requests.get(url,headers=headers) r.raise_for_status() data=json.loads(r.text) #转化为字典的格式 cfWsh=data['cfWsh'] #行政处罚决定书文号 cfCflb=data['cfCflb'] #处罚类别 cfSy=data['cfSy'] #处罚事由 cfYj=data['cfYj'] #处罚依据 cfXdrMc=data['cfXdrMc'] #行政相对人名称 cfXdrShxym=data['cfXdrShxym'] #统一社会信用代码 cfXdrSfz=data['cfXdrSfz'] #法定代表人居民身份证号 cfFr=data['cfFr'] #法定代表人姓名 cfXzjg=data['cfXzjg'] #处罚结果 cfSxq=data['cfSxq'] #处罚生效期 cfJg=data['cfJg'] #处罚机关 depName=data['depName'] #信息提供部门 publishDate=data['publishDate'] #数据送报时间时间 info=[cfWsh,cfCflb,cfSy,cfYj,cfXdrMc,cfXdrShxym,cfXdrSfz,cfFr,cfXzjg,cfSxq,cfJg,depName,publishDate] self.data_mysql(info) except Exception as e: print(e) def data_mysql(self,info): db=pymysql.connect(host='localhost',port=3306,user='root',passwd='12345678',db='shanxi',charset='utf8') cursor=db.cursor() sql="""insert into info(cfWsh,cfCflb,cfSy,cfYj,cfXdrMc,cfXdrShxym,cfXdrSfz,cfFr,cfXzjg,cfSxq,cfJg,depName,publishDate) values ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}')""".format(info[0],info[1],info[2],info[3],info[4],info[5],info[6],info[7],info[8],info[9],info[10],info[11],info[12]) try: cursor.execute(sql) db.commit() print('行政处罚决定书文号-{}-存入成功!'.format(info[0])) except: db.rollback() print('行政处罚决定书文号-{}-存入失败!'.format(info[0])) start_url='http://www.creditsx.gov.cn/xzcfListNew.jspx' ShanXi=SX() url_list=ShanXi.get_urllist(start_url) for item in url_list: ShanXi.get_info(item)
注:代码过于繁琐,很多地方可以删减的,但是......我太懒了,最近也是事多,导师逼得紧,所以大家可以自己删减~~~
今日爬虫完成!
今日鸡汤:走得顺时,不必太张狂,就算你爬到了坡顶,终究还要走下坡路;走得快时,无须太得意,你的脚力总是有限的,不如放慢脚步把短暂的路走得精彩些;走得累时,莫要太哀叹,要知道歇一歇,经受了劳累,才知道坚强与珍惜;走得苦时,切勿太悲怆,生活里是没有绝路的,苦难是人生的梯。
加油ヾ(◍°∇°◍)ノ゙