分类目录归档:Python

Wagtail demo 安装指南

学习Wagtail最快的办法可能就是下载最新的Demo先进行体验了。

Demo地址:https://github.com/wagtail/bakerydemo

https://github.com/wagtail/bakerydemo.git
cd bakerydemo
pip install -r requirements.txt

Windows下安装可能会出现安装uwsgi提示 module ‘os’ has no attribute ‘uname’。解决办法是修改requirements/production.txt重新运行 pip install -r requirements.txt即可

接下来,我们将设置我们的本地环境变量。我们使用django-dotenv来解决这个问题。它读取位于项目顶层目录中的文件名.env中的环境变量。我们需要启动的唯一变量是DJANGO_SETTINGS_MODULE:

cp bakerydemo/settings/local.py.example bakerydemo/settings/local.py
echo "DJANGO_SETTINGS_MODULE=bakerydemo.settings.local" > .env

修改bakerydemo.settings.local.py中的数据库配置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'bakerydemo',
        'USER': 'postgres',
        'PASSWORD': 'password',
        'HOST': '127.0.0.1',
        'PORT': '5432',
    }
}

要设置数据库并加载初始数据,请运行以下命令:

./manage.py migrate
./manage.py load_initial_data
./manage.py runserver

使用 admin / changeme 登录到管理后台。

Wagtail介绍 — 基于Django的Python CMS

关于Wagtail

Wagtail是一个用Python编写的开源CMS,并构建在Django框架上。它是由开发者为开发者开发的,它为编辑提供了一个快速吸引人的界面,让编辑可以直观地创建和结构化内容。优雅、强大和敏捷——我们对Wagtail能提供的东西感到非常自豪。

为什么使用Wagtail

有很多优秀的开源内容管理系统。我们在大型网站上非常成功地使用Drupal,包括知名的非政府组织、筹款慈善机构、智库、大学和公共部门组织。还有一些优秀的Django CMS,包括Mezzanine, Fein和Django CMS,它们的开发人员社区很好,案例研究也令人印象深刻。

但是,在建立了14年的内容管理网站之后,我们对编辑的经验和CMS的工作方式和结构有了强烈的意见,我们需要通过对现有项目的贡献来管理一个比我们能够实现的更快的发展速度。

Django友好

Django自0.96年以来一直是Andrew Godwin的热情支持者和支持者,我们很自豪地将Django和Django等Django和Django等人都在我们的校友中。

在过去的5年里,Django一直是我们最喜欢的应用程序开发的平台,因为它继续为健壮的、快速的开发和编码乐趣所带来的甜蜜点。

Wagtail 提供

  • 使用标准的Django模板完全控制设计
  • 通过标准的Django模型配置内容类型
  • 与现有的Django应用程序的直接集成。

图像/文档管理

不要打断你的流程来添加媒体——直观设计

权限

简单且可配置,即使是复杂的需求

工作流

包括多站点和多语言支持

使用Wagtail

安装 Wagtail

pip install wagtail

建立站点

wagtail start mysite

设置数据

cd mysite
python manage.py migrate

创建管理账号

python manage.py createsuperuser
python manage.py runserver

现在,你可以登录 http://127.0.0.1:8000/admin/. 开始构建你的站点,或者查看我们的Wagtail10分钟指南

PyMongo基本使用

引用PyMongo

import pymongo

创建连接Connection

import pymongo

conn = pymongo.Connection('localhost',27017)

from pymongo import Connection

conn = Connection('localhost',27017)

创建Connection时,指定host及port参数

import pymongo
conn = pymongo.Connection(host='127.0.0.1',port=27017)

连接数据库

db = conn.ChatRoom

db = conn['ChatRoom']

连接聚集

account = db.Account

或 account = db[“Account”]

查看全部聚集名称

db.collection_names()

查看聚集的一条记录

db.Account.find_one()
db.Account.find_one({"UserName":"keyword"})

查看聚集的字段

db.Account.find_one({},{"UserName":1,"Email":1})
// {u'UserName': u'libing', u'_id': ObjectId('4ded95c3b7780a774a099b7c'), u'Email': u'libing@35.cn'}
db.Account.find_one({},{"UserName":1,"Email":1,"_id":0})
// {u'UserName': u'libing', u'Email': u'libing@35.cn'}

查看聚集的多条记录

for item in db.Account.find():
    item

for item in db.Account.find({"UserName":"libing"}):
    item["UserName"]

查看聚集的记录统计

db.Account.find().count()
db.Account.find({"UserName":"keyword"}).count()

聚集查询结果排序

db.Account.find().sort("UserName")  --默认为升序
db.Account.find().sort("UserName",pymongo.ASCENDING)   --升序
db.Account.find().sort("UserName",pymongo.DESCENDING)  --降序

聚集查询结果多列排序

db.Account.find().sort([("UserName",pymongo.ASCENDING),("Email",pymongo.DESCENDING)])

添加记录

db.Account.insert({"AccountID":21,"UserName":"libing"})

修改记录

db.Account.update({"UserName":"libing"},{"$set":{"Email":"libing@126.com","Password":"123"}})

删除记录

db.Account.remove()   -- 全部删除
db.Test.remove({"UserName":"keyword"})

如何用python实现一个高自由度爬虫

本爬虫有以下几点:

  • 可以爬取一个上亿页面的站点,可以多开,暂停,继续
  • 可以自定义爬行路径,爬行延时
  • 能够自动发现新链接,加入队列

以下为代码:

爬虫配置文件,cnblogs_com.py,可以配置开始页面,爬行页面,保存页面,头信息,延迟,超时时间。

# coding=utf-8

start_urls = [
    'http://www.cnblogs.com/',
    'http://news.cnblogs.com/',
    'http://q.cnblogs.com/',
    'http://home.cnblogs.com/blog/all/',
]
find_urls = [
    r'^http://news\.cnblogs\.com/n/\d+/$',
    r'^http://q.cnblogs.com/q/\d+/$',
    r'^http://www\.cnblogs\.com/[a-zA-Z0-9\-_]+/p/\d+.html$',
    r'^http://www\.cnblogs\.com/[a-zA-Z0-9\-_]+/archive/\d+/\d+/\d+/\d+.html$',
    r'^http://www\.cnblogs\.com/[a-zA-Z0-9\-_]+/$',
    r'^http://www\.cnblogs\.com/[a-zA-Z0-9\-_]+/default\.html\?page=\d+$',
    r'^http://q\.cnblogs\.com/tag/',
]
save_urls = [
    r'^http://news\.cnblogs\.com/n/\d+/$',
    r'^http://q.cnblogs.com/q/\d+/$',
    r'^http://www\.cnblogs\.com/[a-zA-Z0-9\-_]+/p/\d+.html$',
    r'^http://www\.cnblogs\.com/[a-zA-Z0-9\-_]+/archive/\d+/\d+/\d+/\d+.html$',
]
headers = {
    "User-Agent": "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36",
    "Referer": "http://www.hisearch.cn/",
}
delay = 2
timeout = 5

爬虫开始命令行,可以运行 python spider.py -s cnblogs_com start 开始爬取一个站点,也可多开,中间进程挂了下次可以继续爬

#!/usr/bin/python
# coding=utf-8


import argparse
from lib.Spider import Spider

allow_commands = ['start', 'clean']

if __name__ == '__main__':
    # 解析参数
    parser = argparse.ArgumentParser(description='General crawler')
    parser.add_argument('-s', '--site', help='site config file name', required=True)
    parser.add_argument('command', help='|'.join(allow_commands), type=str)
    args = parser.parse_args()
    command = args.command
    # 执行程序
    s = Spider(args.site)
    if command == 'start':
        s.start()
    elif command == 'clean':
        s.clean()
    elif command == 'restart':
        s.restart()
    else:
        print('%s is not in a valid command, allowed: %s' % (command, '|'.join(allow_commands)))

爬虫类: Spider.py 主要采用了leveldb来存储爬取的数据,leveldb能够对抓取的数据进行压缩,用redis做队列,redis的hyperloglog数据格式能够用非常少的内存来做url去重

# coding=utf-8
"""
爬虫类
"""

import time
import sys
import traceback
import logging
from logging.handlers import TimedRotatingFileHandler
import re
import redis
import uuid
import requests
from conf import settings
import leveldb
from lxml.html import fromstring


class Spider(object):
    site = None
    config = None
    que = None
    log = None
    db = None
    request = None

    def __init__(self, site):
        self.site = site
        self.load_config()
        self.que = redis.from_url(settings.REDIS_URI)
        self.log = self.get_logger()
        self.db = leveldb.LevelDB(settings.DATA_DIR + self.site, max_open_files=30)
        self.request = requests.session()

    def start(self):
        if not self.is_started():
            self.que.sadd('running_sites', self.site)
            for url in self.config.start_urls:
                self.que.pfadd(self.site + '_all', url)
                self.que.lpush(self.site + '_in', url)
        self.run()

    def run(self):
        while not self.que_is_empty():
            url = self.que.rpop(self.site + '_in').decode()
            html = self.get_page(url)
            if html is not None:
                data = self.get_data(html, url)
                if data:
                    self.store_data(url, data)
                self.find_more_links(html, url)
            time.sleep(self.config.delay)
        self.finish()

    def que_is_empty(self):
        if self.que.llen(self.site + '_in') == 0:
            return True
        else:
            return False

    def load_config(self):
        self.config = __import__('conf.sites.' + self.site, fromlist=['conf.sites.' + self.site])

    def is_started(self):
        if self.que.sismember('running_sites', self.site):
            self.log.info("%s is started yet." % (self.site))
            return True
        else:
            self.log.info("%s is not start." % (self.site))
            return False

    def get_page(self, url):
        html = None
        try:
            r = self.request.get(url, headers=self.config.headers, timeout=self.config.timeout)
            if r.ok:
                html = r.text
            r.close()
            self.log.debug("page_download: " + url)
        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            self.log.exception("download_error: " + url + ", " + str(exc_value),
                               exc_info=traceback.format_tb(exc_traceback))
        return html

    def get_data(self, html, url):
        for regxp in self.config.save_urls:
            if re.compile(regxp).match(url):
                return html
        return False

    def store_data(self, url, data):
        self.db.Put(url.encode(), data.encode())
        self.log.debug("page_saved: %s" % url)

    def find_more_links(self, html, url):
        try:
            page = fromstring(html, url)
            page.make_links_absolute(url)
            for element, attribute, link, pos in page.iterlinks():
                for regxp in self.config.find_urls:
                    if re.compile(regxp).match(link):
                        self.add_url(link)
                        break
        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            self.log.exception("find_more_links_error: " + url + ", " + str(exc_value),
                               exc_info=traceback.format_tb(exc_traceback))

    def add_url(self, url):
        if self.que.pfadd(self.site + '_all', url) == 1:
            key = url.encode()
            if key not in self.db.RangeIter(include_value=False, key_from=key, key_to=key):
                self.que.lpush(self.site + '_in', url)
                self.log.debug("page_found: " + url)
            else:
                self.log.debug("page_exist: " + url)

    def finish(self):
        self.que.srem('running_sites', self.site)
        self.que.delete(self.site + '_all')
        self.log.info('finished')

    def clean(self):
        self.que.srem('running_sites', self.site)
        self.que.delete(self.site + '_all')
        self.que.delete(self.site + '_in')
        self.log.info('cleaned')

    def restart(self):
        self.clean()
        self.start()

    def get_logger(self):
        logger = logging.getLogger('spider.' + self.site)
        hd = TimedRotatingFileHandler(settings.LOG_DIR + self.site + '.log', when='D', backupCount=30)
        formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
        hd.setFormatter(formatter)
        logger.addHandler(hd)
        logger.setLevel(logging.DEBUG)
        return logger

    def get_doc_id_by_url(self, url):
        return str(uuid.uuid5(uuid.NAMESPACE_URL, url))

python 清理html

def clean_html(html):
    """
    Copied from NLTK package.
    Remove HTML markup from the given string.

    :param html: the HTML string to be cleaned
    :type html: str
    :rtype: str
    """

    # First we remove inline JavaScript/CSS:
    cleaned = re.sub(r"(?is)<(script|style).*?>.*?(</\1>)", "", html.strip())
    # Then we remove html comments. This has to be done before removing regular
    # tags since comments can contain '>' characters.
    cleaned = re.sub(r"(?s)<!--(.*?)-->[\n]?", "", cleaned)
    # Next we can remove the remaining tags:
    cleaned = re.sub(r"(?s)<.*?>", " ", cleaned)
    # Finally, we deal with whitespace
    cleaned = re.sub(r" ", " ", cleaned)
    cleaned = re.sub(r"  ", " ", cleaned)
    cleaned = re.sub(r"  ", " ", cleaned)
    return cleaned.strip()

HTMLPrinter

Python set 数据类型

python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)等数学运算.

sets 支持 x in set, len(set),和 for x in set。作为一个无序的集合,sets不记录元素位置或者插入点。因此,sets不支持 indexing, slicing, 或其它类序列(sequence-like)的操作。



下面来点简单的小例子说明把。

>>> x = set('spam')
>>> y = set(['h','a','m'])
>>> x, y
(set(['a', 'p', 's', 'm']), set(['a', 'h', 'm']))

再来些小应用。

>>> x & y # 交集
set(['a', 'm'])

>>> x | y # 并集
set(['a', 'p', 's', 'h', 'm'])

>>> x - y # 差集
set(['p', 's'])

记得以前个网友提问怎么去除海量列表里重复元素,用hash来解决也行,只不过感觉在性能上不是很高,用set解决还是很不错的,示例如下:

>>> a = [11,22,33,44,11,22]
>>> b = set(a)
>>> b
set([33, 11, 44, 22])
>>> c = [i for i in b]
>>> c
[33, 11, 44, 22]

很酷把,几行就可以搞定。

1.8 集合 

集合用于包含一组无序的对象。要创建集合,可使用set()函数并像下面这样提供一系列的项:



s = set([3,5,9,10])      #创建一个数值集合

t = set("Hello")         #创建一个唯一字符的集合



与列表和元组不同,集合是无序的,也无法通过数字进行索引。此外,集合中的元素不能重复。例如,如果检查前面代码中t集合的值,结果会是:



>>> t

set(['H', 'e', 'l', 'o'])



注意只出现了一个'l'。

集合支持一系列标准操作,包括并集、交集、差集和对称差集,例如:



a = t | s          # t 和 s的并集

b = t & s          # t 和 s的交集

c = t – s          # 求差集(项在t中,但不在s中)

d = t ^ s          # 对称差集(项在t或s中,但不会同时出现在二者中)



基本操作:

t.add('x')            # 添加一项

s.update([10,37,42])  # 在s中添加多项



使用remove()可以删除一项:

t.remove('H')



len(s)
set 的长度

x in s
测试 x 是否是 s 的成员

x not in s
测试 x 是否不是 s 的成员

s.issubset(t)
s <= t
测试是否 s 中的每一个元素都在 t 中

s.issuperset(t)
s >= t
测试是否 t 中的每一个元素都在 s 中

s.union(t)
s | t
返回一个新的 set 包含 s 和 t 中的每一个元素

s.intersection(t)
s & t
返回一个新的 set 包含 s 和 t 中的公共元素

s.difference(t)
s - t
返回一个新的 set 包含 s 中有但是 t 中没有的元素

s.symmetric_difference(t)
s ^ t
返回一个新的 set 包含 s 和 t 中不重复的元素

s.copy()
返回 set “s”的一个浅复制


请注意:union(), intersection(), difference() 和 symmetric_difference() 的非运算符(non-operator,就是形如 s.union()这样的)版本将会接受任何 iterable 作为参数。相反,它们的运算符版本(operator based counterparts)要求参数必须是 sets。这样可以避免潜在的错误,如:为了更可读而使用 set('abc') & 'cbs' 来替代 set('abc').intersection('cbs')。从 2.3.1 版本中做的更改:以前所有参数都必须是 sets。

另外,Set 和 ImmutableSet 两者都支持 set 与 set 之间的比较。两个 sets 在也只有在这种情况下是相等的:每一个 set 中的元素都是另一个中的元素(二者互为subset)。一个 set 比另一个 set 小,只有在第一个 set 是第二个 set 的 subset 时(是一个 subset,但是并不相等)。一个 set 比另一个 set 打,只有在第一个 set 是第二个 set 的 superset 时(是一个 superset,但是并不相等)。

子 set 和相等比较并不产生完整的排序功能。例如:任意两个 sets 都不相等也不互为子 set,因此以下的运算都会返回 False:a<b, a==b, 或者a>b。因此,sets 不提供 __cmp__ 方法。

因为 sets 只定义了部分排序功能(subset 关系),list.sort() 方法的输出对于 sets 的列表没有定义。


运算符
   运算结果

hash(s)
   返回 s 的 hash 值


下面这个表列出了对于 Set 可用二对于 ImmutableSet 不可用的运算:

运算符(voperator)
等价于
运算结果

s.update(t)
s |= t
返回增加了 set “t”中元素后的 set “s”

s.intersection_update(t)
s &= t
返回只保留含有 set “t”中元素的 set “s”

s.difference_update(t)
s -= t
返回删除了 set “t”中含有的元素后的 set “s”

s.symmetric_difference_update(t)
s ^= t
返回含有 set “t”或者 set “s”中有而不是两者都有的元素的 set “s”

s.add(x)

向 set “s”中增加元素 x

s.remove(x)

从 set “s”中删除元素 x, 如果不存在则引发 KeyError

s.discard(x)

如果在 set “s”中存在元素 x, 则删除

s.pop()

删除并且返回 set “s”中的一个不确定的元素, 如果为空则引发 KeyError

s.clear()

删除 set “s”中的所有元素


请注意:非运算符版本的 update(), intersection_update(), difference_update()和symmetric_difference_update()将会接受任意 iterable 作为参数。从 2.3.1 版本做的更改:以前所有参数都必须是 sets。

还请注意:这个模块还包含一个 union_update() 方法,它是 update() 方法的一个别名。包含这个方法是为了向后兼容。程序员们应该多使用 update() 方法,因为这个方法也被内置的 set() 和 frozenset() 类型支持。

python音、视频处理

http://zulko.github.io/moviepy/index.html

MoviePy is a Python module for video editing, which can be used for basic operations (like cuts, concatenations, title insertions), video compositing (a.k.a. non-linear editing), video processing, or to create advanced effects. It can read and write the most common video formats, including GIF.

https://wiki.python.org/moin/AudioVideo

Audio and Video

Some Python-based projects related to audio and video. See also Screencasting.

Audio/Music Editors

Jokosher – a complete application for recording, editing, mixing and exporting audio
See also PythonInMusic for more projects.

Audio/Music Players

FUPlayer – a music player with management and CD ripping/burning capabilities
Listen – an audio player with music management features
Quod Libet – an audio player with scalable management of music collections (more than “a mere 10000 songs”)
TimPlayer – a PyGTK based music player using GStreamer (see http://creationix.com/OpenSource/TimPlayer/)
Libraries and Frameworks

GStreamer – an audio/video playback framework – has Python bindings
MLT – an open source multimedia framework, designed and developed for television broadcasting – has Python bindings
MoviePy – a Python library for script-based movie editing (cuts, concatenations, text insertion, non-linear editing)
See also Audio for details of Python audio libraries.

Media Centres

Elisa – an open source cross-platform media centre solution
Freevo – Linux multimedia jukebox
Streaming

Boxtream – a mobile and autonomous audio and video streaming and recording studio (uses GStreamer)
Flumotion – a streaming media server (uses GStreamer)
Video Editors

OpenShot – an open source video editor, written in Python and based on MLT and PyGtk
Pitivi – an open source video editor, written in Python and based on GStreamer and GTK+

python rest Web browsable API

Django REST framework

Django REST framework is a powerful and flexible toolkit for building Web APIs.

Some reasons you might want to use REST framework:

The Web browsable API is a huge usability win for your developers.
Authentication policies including packages for OAuth1a and OAuth2.
Serialization that supports both ORM and non-ORM data sources.
Customizable all the way down – just use regular function-based views if you don’t need the more powerful features.
Extensive documentation, and great community support.
Used and trusted by large companies such as Mozilla and Eventbrite.

flask-restful-swagger

flask-restful-swagger is a wrapper for flask-restful which enables swagger support.

In essense, you just need to wrap the Api instance and add a few python decorators to get full swagger support.

Flask API

Flask API is an implementation of the same web browsable APIs that Django REST framework provides.

It gives you properly content negotiated responses and smart request parsing.

It is currently a work in progress, but the fundamentals are in place and you can already start building kick-ass browsable Web APIs with it. If you want to start using Flask API right now go ahead and do so, but be sure to follow the release notes of new versions carefully.

python+logstash+elasticsearch+Kibana日志方案

python用的是python-logstash库https://github.com/vklochan/python-logstash

这一套用起来都比较方便.

logstash安装,配置,运行

下载并安装logstash

打开https://www.elastic.co/downloads/logstash,找到最新版下载链接,使用wget下载rpm,然后通过yum安装

wget https://download.elastic.co/logstash/logstash/packages/centos/logstash-2.1.1-1.noarch.rpm
yum install logstash-2.1.1-1.noarch.rpm

也可以直接通过repo安装:https://www.elastic.co/guide/en/logstash/current/package-repositories.html

配置logstash

vim /etc/logstash/conf.d/logstash.conf

input {  
  tcp {
    port => 5959
    codec => json
  }  
}
output {
  elasticsearch { hosts => ["localhost:9200"] }
}

运行logstash

chkconfig logstash on
/etc/init.d/logstash start
telnet 127.0.0.1 5959 #test

Python logstash

安装python包

pip install python-logstash

测试脚本 vim test.py

import logging
import logstash
import sys

host = 'localhost'

test_logger = logging.getLogger('python-logstash-logger')
test_logger.setLevel(logging.DEBUG)
test_logger.addHandler(logstash.TCPLogstashHandler(host, 5959, version=1))

test_logger.error('python-logstash: test logstash error message.')
test_logger.info('python-logstash: test logstash info message.')
test_logger.warning('python-logstash: test logstash warning message.')

extra = {
    'test_string': 'python version: ' + repr(sys.version_info),
    'test_boolean': True,
    'test_dict': {'a': 1, 'b': 'c'},
    'test_float': 1.23,
    'test_integer': 123,
    'test_list': [1, 2, '3'],
}
test_logger.info('python-logstash: test extra fields', extra=extra)

检查是否成功

curl http://127.0.0.1:9200/_search?pretty&q=logstash

kibana安装使用

https://www.elastic.co/downloads/kibana找到最新版本的kibana

wget https://download.elastic.co/kibana/kibana/kibana-4.3.1-linux-x64.tar.gz
tar -zxf kibana-4.3.1-linux-x64.tar.gz

vim config/kibana.yml,找到elasticsearch.url这行,根据情况决定是否要修改,如果修改记得去掉前面的注释符号

运行bin/kibana启动服务,访问http://127.0.0.1:5601/,点击创建即可

配置nginx访问

安装htpasswd工具,生成账号密码

 yum install httpd-tools
 htpasswd -b -c /data/kibana.htpasswd username password

配置nginx server

upstream kibana {
    server 127.0.0.1:5601 fail_timeout=0;
}

server {
    listen      80;
    server_name          kibana.domain.com;

    location / {
        auth_basic "Restricted";
        auth_basic_user_file /data/kibana.htpasswd;
        proxy_pass http://kibana;
   }
}

重启nginx

nginx -s reload

使用elementtree处理大的xml

这个xml超过了30G,关键是iterparse以及e.clear()

from elementtree.ElementTree import iterparse
from datetime import datetime
import redis
import json
import lxml.html
import re
import traceback
import time
import cgi


def main():
    redisConn = redis.from_url("redis://localhost:6379/0")
    i = 0
    xmlfile = "/data/download/Posts.xml"
    for event, e in iterparse(xmlfile):
        if e.tag == "row" and e.get("PostTypeId") == "1":
            try:
                data = {
                    "url": "http://stackoverflow.com/questions/" + e.get("Id"),
                    "title": cgi.escape(e.get("Title")),
                    "content": cgi.escape(lxml.html.fromstring(e.get("Body")).text_content()),
                    "tags": cgi.escape(",".join(re.findall("<([^>]+)>", e.get("Tags")))),
                    'site': 'stackoverflow',
                    "timestamp": datetime.now().isoformat()
                }
                redisConn.lpush('ResultQueue', json.dumps(data))
            except:
                traceback.print_exc()
                print e.attrib
                continue
        i += 1
        if i % 1000 == 0:
            time.sleep(5);
            print i
        e.clear()


if __name__ == '__main__':
    main()