用Python实现的一个简单的爬取省市乡镇的行政区划信息的脚本
# coding=utf-8
# Creeper
import os
import bs4
import time
import MySQLdb
import urllib2
import datetime
import warnings
import traceback
import ConfigParser
try:
basedir = os.path.dirname(os.path.abspath(__file__))
except NameError:
import sys
basedir = os.path.dirname(os.path.abspath(sys.argv[0]))
SETTINGS_FILE = os.path.join(basedir, 'settings.ini')
GLOBAL_CONFIG = {
'server': {
'debug': False,
},
'db': {
'host': '127.0.0.1',
'port': '3306',
'user': 'root',
'password': '',
'dbname': 'test',
'table': 'group'
}
}
def __config(item):
GLOBAL_CONFIG[sec][item[0]] = item[1]
try:
parser = ConfigParser.ConfigParser()
parser.readfp(open(SETTINGS_FILE))
for sec in parser.sections():
map(__config, parser.items(sec))
except:
print 'settings.ini needed'
raise
N = 0
class Handle(object):
def __init__(self, *args, **kwargs):
super(Handle, self).__init__()
self.db = {}
self.conn = None
self.cursor = None
self._cursor(**kwargs)
def _cursor(self, **kwargs):
self.db.update(**kwargs)
host = kwargs.get('host', '127.0.0.1')
port = int(kwargs.get('port', 3306))
user = kwargs.get('user', 'root')
pwd = kwargs.get('password', '')
dbname = kwargs.get('dbname', 'test')
charset = kwargs.get('charset', 'utf8')
_conn = MySQLdb.connect(user=user, passwd=pwd,
host=host, port=port, charset=charset)
try:
_conn.select_db(dbname)
except:
sql = """CREATE DATABASE IF NOT EXISTS `%s` DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
""" % dbname
_conn.cursor().execute(sql)
_conn.select_db(dbname)
self.conn = _conn
self.cursor = _conn.cursor()
def format_pk(self, pk, index):
d = {1:2, 2:4, 3:6, 4:9, 5:12}
try:
pk = int(float(pk))
except:
raise ValueError, 'the primary key must be integer or string interger'
return int(str(pk)[:d[index]])
while (pk * 1.0 / 10).is_integer():
pk = pk * 1.0 / 10
return pk < 10 and int(pk) * 10 or int(pk)
def do_execute(self, pk, name, type, parent='NULL'):
global N
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S %f')
if N%100 == 0 and N != 0:
print 'Total: %s ---%s' % (N, now)
# time.sleep(5)
if not parent or parent == '':
parent = 'NULL'
sql = """INSERT INTO `%s` (`id`, `name`, `type`, `parent`) VALUES(%s, '%s', '%s', %s);
""" % (self.db['table'], pk, name, type, parent)
try:
self.cursor.execute(sql)
self.conn.commit()
print '+',
N += 1
except MySQLdb.Warning, w:
print "\nWarning:%s" % str(w)
print '#',
except MySQLdb.Error, e:
if not 'Duplicate entry' in str(e):
print "\nError:%s" % str(e)
self.debug(pk, name)
self.debug(pk, parent)
else:
print '=',
self.debug(pk, name)
except:
traceback.print_exc()
print '?',
def do_executemany(self, items, params=None):
sql = """INSERT INTO `%s` (`id`, `name`, `type`, `parent`) VALUES """ % self.db['table']
sql +="(%s, %s, %s, %s)";
try:
self.cursor.executemany(sql, items)
self.conn.commit()
except MySQLdb.Error, e:
print "Error:%s" % str(e)
except:
traceback.print_exc()
class Creeper(Handle):
def __init__(self, *args, **kwargs):
Handle.__init__(self, *args, **kwargs)
self.init_db()
self.root_url = ''
self._type = {1:'province',2:'city',3:'county',4:'town',5:'village'}
def init_db(self):
__sql = """CREATE TABLE IF NOT EXISTS `%s` (
`id` bigint(20) NOT NULL,
`name` varchar(30) NOT NULL,
`type` varchar(30) NOT NULL,
`parent` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `Group_12345` (`name`),
KEY `Group_67890` (`parent`),
FOREIGN KEY(parent) REFERENCES `%s` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
""" % (self.db['table'], self.db['table'])
try:
self.cursor.execute(__sql)
self.cursor.execute("""CREATE TABLE IF NOT EXISTS `debug` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`badid` bigint(20) NOT NULL,
`others` varchar(256) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;""")
self.conn.commit()
except MySQLdb.Warning, w:
if not 'already exists' in str(w):
print "Warning:%s" % str(w)
except MySQLdb.Error, e:
print "Error:%s" % str(e)
traceback.print_exc()
except:
traceback.print_exc()
pass
def debug(self, *args):
try:
_sql = """INSERT INTO `debug` (`badid`, `others`) VALUES(%s, '%s');
""" % (args[0], args[1])
self.cursor.execute(_sql)
self.conn.commit()
except:
traceback.print_exc()
finally:
return
def __get_url(self, tup, index):
id = tup[0]
parent = tup[-1]
__url = []
for i in range(0, index, 2):
__url.append(str(id)[i: i+2])
__url.append(str(id))
return self.root_url + '/'.join(__url) + '.html'
def format_tag(self, x_tag, url, index, limit=None):
if limit and index > limit: return
parent = str(url.split('/2013/')[1].split('/')[-1])[:-5]
__type = self._type[index]
__parent = not parent and 'NULL' or parent
if isinstance(x_tag, bs4.element.Tag) and x_tag.has_attr('href'):
print '.',
href = x_tag['href']
child_url = '/'.join(url.split('/')[:-1])
full_url = '/'.join([child_url, href])
__pk = self.format_pk(href.split('.html')[0].split('/')[-1], index)
__name = x_tag.text
i = (__pk, __name, __type, __parent)
self.do_execute(*i)
self.get_info(full_url, index + 1, limit)
else:
print '*',
__pk = self.format_pk(x_tag[0].text, index)
__name = x_tag[1].text
self.do_execute(__pk, __name, __type, __parent)
def get_info(self, url, index, limit=None):
# 解析页面,获取目标区域的数据
# 获取单元数据,格式化为可供插入数据库的元组
try:
__html = urllib2.urlopen(url).read()
__soup = bs4.BeautifulSoup(__html, from_encoding='gbk')
__tr = __soup('tr', class_='%str' % self._type[index])
except:
try:
self.debug(0, url)
except:
traceback.print_exc()
finally:
return
__lst = []
for tr in __tr:
# 每个tr中的多个td代表多个省
if index == 1:
for td in tr('td'):
__lst.extend(td('a'))
continue
# 每个tr中的多个td代表一个节点,取最后一个td中的a标签
if tr('td')[-1]('a'):
__lst.extend(tr('td')[-1]('a'))
else:
# 没有子节点的元素,单纯的通过td中的数据创建
self.format_tag([tr('td')[0], tr('td')[-1]], url, index, limit)
for a in __lst:
self.format_tag(a, url, index, limit)
def do_get_childs(self, index):
# 1. 查询获取当前层级节点数目
_sql = """SELECT COUNT( * ) FROM `%s` WHERE `type`='%s';
""" % (self.db['table'], self._type[index])
self.cursor.execute(_sql)
total = self.cursor.fetchone()[0]
# 2. 遍历父节点,获取子节点数据
for i in range(0, total, 30):
_sql = """SELECT `id`, `parent` FROM `%s` WHERE `type` = '%s' LIMIT %s, %s;
""" % (self.db['table'], self._type[index], i, i+30)
self.cursor.execute(_sql)
id_and_parent = list(set(self.cursor.fetchall()))
for tup in id_and_parent:
url = self.__get_url(tup, index)
self.get_info(url, index+1)
warnings.filterwarnings('error', category = MySQLdb.Warning)
del warnings
if __name__ == '__main__':
url = "http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/"
db_config = GLOBAL_CONFIG['db']
g = Creeper(**db_config)
g.root_url = url
g.init_db()
lst = g.get_info(url, index=1, limit=5)
# g.do_get_childs(3)
用Python实现的一个简单的爬取省市乡镇的行政区划信息的脚本的更多相关文章
- 【python爬虫】一个简单的爬取百家号文章的小爬虫
需求 用"老龄智能"在百度百家号中搜索文章,爬取文章内容和相关信息. 观察网页 红色框框的地方可以选择资讯来源,我这里选择的是百家号,因为百家号聚合了来自多个平台的新闻报道.首先看 ...
- Python爬虫——使用 lxml 解析器爬取汽车之家二手车信息
本次爬虫的目标是汽车之家的二手车销售信息,范围是全国,不过很可惜,汽车之家只显示100页信息,每页48条,也就是说最多只能够爬取4800条信息. 由于这次爬虫的主要目的是使用lxml解析器,所以在信息 ...
- 一个简单的爬取b站up下所有视频的所有评论信息的爬虫
心血来潮搞了一个简单的爬虫,主要是想知道某个人的b站账号,但是你知道,b站在搜索一个用户时,如果这个用户没有投过稿,是搜不到的,,,这时就只能想方法搞到对方的mid,,就是 space.bilibil ...
- Python爬虫初探 - selenium+beautifulsoup4+chromedriver爬取需要登录的网页信息
目标 之前的自动答复机器人需要从一个内部网页上获取的消息用于回复一些问题,但是没有对应的查询api,于是想到了用脚本模拟浏览器访问网站爬取内容返回给用户.详细介绍了第一次探索python爬虫的坑. 准 ...
- python定义的一个简单的shell函数的代码
把写代码过程中经常用到的一些代码段做个记录,如下代码段是关于python定义的一个简单的shell函数的代码. pipe = subprocess.Popen(cmd, stdout=subproce ...
- Python爬虫学习三------requests+BeautifulSoup爬取简单网页
第一次第一次用MarkDown来写博客,先试试效果吧! 昨天2018俄罗斯世界杯拉开了大幕,作为一个伪球迷,当然也得为世界杯做出一点贡献啦. 于是今天就编写了一个爬虫程序将腾讯新闻下世界杯专题的相关新 ...
- 使用python爬取MedSci上的期刊信息
使用python爬取medsci上的期刊信息,通过设定条件,然后获取相应的期刊的的影响因子排名,期刊名称,英文全称和影响因子.主要过程如下: 首先,通过分析网站http://www.medsci.cn ...
- Python爬虫开源项目代码,爬取微信、淘宝、豆瓣、知乎、新浪微博、QQ、去哪网等 代码整理
作者:SFLYQ 今天为大家整理了32个Python爬虫项目.整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心.所有链接指向GitHub,祝大家玩的愉快 1.WechatSogou [ ...
- 零基础爬虫----python爬取豆瓣电影top250的信息(转)
今天利用xpath写了一个小爬虫,比较适合一些爬虫新手来学习.话不多说,开始今天的正题,我会利用一个案例来介绍下xpath如何对网页进行解析的,以及如何对信息进行提取的. python环境:pytho ...
随机推荐
- 解决@media screen (自适应)IE浏览器不兼容问题
1.解决兼容性问题 (1)页面最顶部必须定义:<!DOCTYPE html> (2)点击:下载 respond.js 文件 (3)引入<script src="respon ...
- ios xcode如何在控制台打印frame
进入正题 打开终端输入三条命令: 1. touch ~/.lldbinit 2. echo display @import UIKit >> ~/.lldbinit 3. echo tar ...
- Foundation与coreFoundation的相互转换
今天在整理以前的一些琐碎知识,今天就分享一个Foundation与coreFoundation的相互转换细节问题,其中的引用计数器是需要考虑的方面. ARC 环境下,CoreFoundation框 ...
- Ubuntu14.04搭建cocos2dx2.2.5开发环境(超级具体)
一 下载解压 官方下载地址:http://www.cocos2d-x.org/download 下载下来之后解压完毕之后会得到一个文件夹cocos2d-x-2.2.5 二 编译 1 安装依赖 cd到c ...
- 【MongoDB安装和基础学习系列】
转:http://www.cnblogs.com/lipan/archive/2011/03/08/1977691.html 系列目录 MongoDB学习笔记(一) MongoDB介绍及安装 ...
- Linux下搭建Oracle11g RAC(6)----安装Grid Infrastructure
从此步骤开始,我们正式安装Grid软件: ① 以grid用户登录图形界面,执行/home/grid/grid/runInstaller,进入OUI的图形安装界面: ② 进入OUI安装界面后,选择第3项 ...
- Java基础知识强化之IO流笔记30:字节流4种方式复制mp4并测试效率
1. 需求:把e:\\哥有老婆.mp4 复制到当前项目目录下的copy.mp4中 字节流四种方式复制文件: • 基本字节流一次读写一个字节 • 基本字节流一次读写一个字节数组 • 高效字节流一次读写一 ...
- as3 打开窗口类
package FlashCode.utils{ import flash.display.Sprite; import flash.net.URLRequest; import flash.net. ...
- springMVC+freemarker中Could not resolve view with name... 问题解决
用到springMVC+freemarker,自己在做demo过程中报: 严重: Servlet.service() for servlet springmvc threw exception jav ...
- final----这篇文章是我收获很大
final 用于声明属性.方法和类,分别表示属性不可变,方法不可重写,类不可继承. [转]Java final 修饰符知识点总结 final从字面上理解含义为“最后的,最终的”.在Java中也同样表示 ...