3分钟Python爬取9000张表情包图片

先看下我的爬取成果:

本视频的演示步骤:

  1. 使用requests爬取200个网页
  2. 使用BeautifulSoup实现图片的标题和地址解析
  3. 将图片下载到本地目录

这2个库的详细用法,请看我的其他视频课程

import requests
from bs4 import BeautifulSoup
import re

1、下载共200个页面的HTML

def download_all_htmls():
    """
    下载所有列表页面的HTML,用于后续的分析
    """
    htmls = []
    for idx in range(200):
        url = f"https://fabiaoqing.com/biaoqing/lists/page/{idx+1}.html"
        print("craw html:", url)
        r = requests.get(url)
        if r.status_code != 200:
            raise Exception("error")
        htmls.append(r.text)
    print("success")
    return htmls
# 执行爬取
htmls = download_all_htmls()
craw html: https://fabiaoqing.com/biaoqing/lists/page/1.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/2.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/3.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/4.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/188.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/189.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/190.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/191.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/192.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/193.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/194.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/195.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/196.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/197.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/198.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/199.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/200.html
success
htmls[0][:1000]
'<html>\n\n<head>\n    <meta charset="UTF-8">\n    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">\n    <meta http-equiv="X-UA-Compatible" content="IE=edge">\n    <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n    <title>热门表情_发表情,表情包大全fabiaoqing.com</title>\n    <meta name="Keywords" content="热门表情,表情包,聊天表情,微信表情包,QQ表情包,发表情,表情包大全,表情包下载,表情下载,表情包大战,贴吧表情包,表情包集中营,斗图">\n    <meta name="Description" content="全网热门表情。发表情,最大最全的表情包网站,分享最新最热的表情包、聊天表情、微信表情包、QQ表情包、金馆长表情包、蘑菇头表情包等各类表情。">\n    <meta name="referrer" content="no-referrer" />\n    <link rel="stylesheet" type="text/css" href="//lib.baomitu.com/semantic-ui/2.2.2/semantic.min.css" />\n    <link rel="stylesheet" type="text/css" href="/Public/css/fbq.css?v=2018" />\n    <script data-ad-client="ca-pub-5486123269162001" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>\n    <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.'

2、解析HTML得到所有的图片标题和URL地址

def parse_single_html(html):
    """
    解析单个HTML,得到数据
    @return list((img_title, img_url))
    """
    soup = BeautifulSoup(html, 'html.parser')
    img_divs = soup.find_all("div", class_="tagbqppdiv")
    datas = []
    for img_div in img_divs:
        img_node = img_div.find("img")
        if not img_node: continue
        datas.append((img_node["title"], img_node["data-original"]))
    return datas
import pprint
pprint.pprint(parse_single_html(htmls[0])[:10])
[('阿弥陀佛,施主放下骂图,立地成佛!',
  'http://ww2.sinaimg.cn/bmiddle/9150e4e5gy1g6qlfb10avj20d70f7gmf.jpg'),
 ('看见你就烦(草莓果酱ox白眼 GIF 动图表情包)',
  'http://wx1.sinaimg.cn/bmiddle/006APoFYly1g68tiftpbmg30bh0bh4o5.gif'),
 ('我在哭', 'http://wx3.sinaimg.cn/bmiddle/006qir4ogy1g54eoes2q2j309q09cdgh.jpg'),
 ('我的人生只要这样躺着混日子就很幸福了',
  'http://ww4.sinaimg.cn/bmiddle/9150e4e5gy1g6qm7x6fiuj20mw0mmt9y.jpg'),
 ('草莓果酱ox动图表情包',
  'http://wx1.sinaimg.cn/bmiddle/ceeb653ely1g64664qyc0g20bf0br4jn.gif'),
 ('噗呲 放屁(沙雕羊驼动图表情包)',
  'http://wx1.sinaimg.cn/bmiddle/78b88159gy1g69cze2hkkg20bp0bpx0y.gif'),
 ('来群里转转(熊猫头旋转 GIF 动图)',
  'http://wx1.sinaimg.cn/bmiddle/ceeb653ely1g68tzab8xng207608wwou.gif'),
 ('我爱你(草莓果酱oxGIF 动图表情包)',
  'http://wx2.sinaimg.cn/bmiddle/006APoFYly1g68uwg8djlg30b60b6e57.gif'),
 ('锁屏 带薪拉屎',
  'http://wx3.sinaimg.cn/bmiddle/ceeb653ely1g654hwdsjkg20dc0avgm4.gif'),
 ('我要可爱死你(草莓果酱ox表情包)',
  'http://wx2.sinaimg.cn/bmiddle/bf976b12gy1g68hx2gtleg208c08bk8q.gif')]
# 执行所有的HTML页面的解析
all_imgs = []
for html in htmls:
    all_imgs.extend(parse_single_html(html))
all_imgs[:10]
[('阿弥陀佛,施主放下骂图,立地成佛!',
  'http://ww2.sinaimg.cn/bmiddle/9150e4e5gy1g6qlfb10avj20d70f7gmf.jpg'),
 ('看见你就烦(草莓果酱ox白眼 GIF 动图表情包)',
  'http://wx1.sinaimg.cn/bmiddle/006APoFYly1g68tiftpbmg30bh0bh4o5.gif'),
 ('我在哭', 'http://wx3.sinaimg.cn/bmiddle/006qir4ogy1g54eoes2q2j309q09cdgh.jpg'),
 ('我的人生只要这样躺着混日子就很幸福了',
  'http://ww4.sinaimg.cn/bmiddle/9150e4e5gy1g6qm7x6fiuj20mw0mmt9y.jpg'),
 ('草莓果酱ox动图表情包',
  'http://wx1.sinaimg.cn/bmiddle/ceeb653ely1g64664qyc0g20bf0br4jn.gif'),
 ('噗呲 放屁(沙雕羊驼动图表情包)',
  'http://wx1.sinaimg.cn/bmiddle/78b88159gy1g69cze2hkkg20bp0bpx0y.gif'),
 ('来群里转转(熊猫头旋转 GIF 动图)',
  'http://wx1.sinaimg.cn/bmiddle/ceeb653ely1g68tzab8xng207608wwou.gif'),
 ('我爱你(草莓果酱oxGIF 动图表情包)',
  'http://wx2.sinaimg.cn/bmiddle/006APoFYly1g68uwg8djlg30b60b6e57.gif'),
 ('锁屏 带薪拉屎',
  'http://wx3.sinaimg.cn/bmiddle/ceeb653ely1g654hwdsjkg20dc0avgm4.gif'),
 ('我要可爱死你(草莓果酱ox表情包)',
  'http://wx2.sinaimg.cn/bmiddle/bf976b12gy1g68hx2gtleg208c08bk8q.gif')]
len(all_imgs)
8999

3、下载图片到本地目录

for idx, (title, img_url) in enumerate(all_imgs):
    # 移除标点符号,只保留中文、大小写字母和阿拉伯数字
    reg = "[^0-9A-Za-z\u4e00-\u9fa5]"
    title = re.sub(reg, '', title)

    # 发现了超长的图片标题,做截断
    if len(title)>10: title = title[:10]

    # 得到jpg还是gif后缀
    post_fix = img_url[-3:]
    filename = f"./output/{title}.{post_fix}"

    print(idx, filename)
    img_data = requests.get(img_url)
    with open(filename,"wb")as f:
        f.write(img_data.content)

print("success")
0 ./output/阿弥陀佛施主放下骂图.jpg
1 ./output/看见你就烦草莓果酱o.gif
2 ./output/我在哭.jpg
3 ./output/我的人生只要这样躺着.jpg
4 ./output/草莓果酱ox动图表情.gif
5 ./output/噗呲放屁沙雕羊驼动图.gif
6 ./output/来群里转转熊猫头旋转.gif
7 ./output/我爱你草莓果酱oxG.gif
8 ./output/锁屏带薪拉屎.gif
9 ./output/我要可爱死你草莓果酱.gif
10 ./output/我尼玛傻了都.jpg
11 ./output/你今天表现蛮好10分.gif
12 ./output/真烦人得找个理由做她.gif
13 ./output/哇哦草莓果酱ox表情.jpg
14 ./output/哥哥又说笑了乔碧萝表.gif
15 ./output/锁屏带薪拉屎.gif
16 ./output/我简直难上加难麻将表.jpg

本文有配套视频讲解,关注公众号:蚂蚁学Python观看

怎样借助Python爬虫给宝宝起个好名字

2019-03-31更新:

代码的python3简化版本:

https://github.com/peiss/chinese-name-score/tree/master/chinese-name-score/python3

代码的视频讲解(我的付费视频课程中的一节):

https://www.iqiyi.com/v_19rsj1yvy8.html


每个人一生中都会遇到一件事情,在事情出现之前不会关心,但是事情一旦来临就发现它极其重要,并且需要在很短的时间内做出重大决定,那就是给自己的新生宝宝起个名字。

因为要在孩子出生后两周内起个名字(需要办理出生证明了),估计很多人都像我一样,刚开始是很慌乱的,虽然感觉汉字非常的多随便找个字做名字都行,后来才发现真不是随便的事情,怎么想都发现不合适,于是到处翻词典、网上搜、翻唐诗宋词、诗经、甚至武侠小说,然而想了很久得到的名字,往往却受到家属的意见和反对,比如不顺口、和亲戚重名重音等问题,这样就陷入了重复寻找和否定的循环,越来越混乱。

于是我们再次回到网上各种搜索,找到很多网上给出的“男宝宝好听的名字大全”之类的文章,这些文章一下子给出几百上千个名字,看的眼花缭乱没法使用。而有不少的测名字的网站或者APP,输入名字能给出八字或者五格的评分,这样的功能感觉还挺好的能给个参考,然而要么我们需要一个个名字的输入进行测试、要么这些网站或者APP自身的名字很少、要么不能满足我们的需求比如限定字、要么就开始收费,到最后也找不到一个好用的。

于是我想做这么一个程序:

  1. 主要的功能,是给出批量名字提供参考,这些名字是结合宝宝的生辰八字算出来的;
  2. 自己可以扩充名字库,比如网上发现了一批诗经里的好名字,想看看怎么样,添加进去就能用;
  3. 可以限定名字的使用字,比如有的家族谱有限定,当前是“国”字辈,名字中必须有“国”字;
  4. 名字列表可以给出评分,这样倒排后就可以从高分往低分来看名字;

通过这种方式可以得到一份符合自己孩子生辰八字、自己的家谱限制、以及自己喜好的名字列表,并且该列表已经给出了分数用于参考,以此为基准我们可以挨个琢磨找出心仪的名字。当然如果有新的想法,随时可以把新的名字添加到词库里面,进行重新计算。

程序的代码结构

代码介绍:

  • /chinese-name-score 代码根目录
  • /chinese-name-score/main 代码目录
  • /chinese-name-score/main/dicts 词典文件目录
  • /chinese-name-score/main/dicts/names_boys_double.txt 词典文件,男孩的双字名字
  • /chinese-name-score/main/dicts/names_boys_single.txt 词典文件,男孩的单字名字
  • /chinese-name-score/main/dicts/names_girls_single.txt 词典文件,女孩的双字名字
  • /chinese-name-score/main/dicts/names_grils_double.txt 词典文件,女孩的单字名字
  • /chinese-name-score/main/outputs 输出数据目录
  • /chinese-name-score/main/outputs/names_girls_source_wxy.txt 输出的示例文件
  • /chinese-name-score/main/scripts 一些对词典文件做预处理的脚本
  • /chinese-name-score/main/scripts/unique_file_lines.py 设定词典文件,对词典中的名字去重和去空白行
  • /chinese-name-score/main/sys_config.py 程序的系统配置,包含爬取得目标URL、词典文件路径
  • /chinese-name-score/main/user_config.py 程序的用户配置,包括宝宝的年月日时分性别等设定
  • /chinese-name-score/main/get_name_score.py 程序的运行入口

使用代码的方法:

  1. 如果没有限定字,就找到词典文件names_boys_double.txt和names_grils_double.txt,可以在这里添加自己找到的一些名字列表,按行分割添加在最后即可;
  2. 如果有限定字,就找到词典文件names_boys_single.txt和names_girls_single.txt,在这里添加自己预先中意的单个字列表,按行分割添加在最后即可;
  3. 打开user_config.py,进行配置,配置项见下一节;
  4. 运行脚本get_name_score.py
  5. 在outputs目录中,查看自己的产出文件,可以复制到Excel,进行排序等操作;

程序的配置入口

程序的配置如下:

# coding:GB18030

"""
在这里写好配置
"""

setting = {}

# 限定字,如果配置了该值,则会取用单字字典,否则取用多字字典
setting["limit_world"] = "国"
# 姓
setting["name_prefix"] = "李"
# 性别,取值为 男 或者 女
setting["sex"] = "男"
# 省份
setting["area_province"] = "北京"
# 城市
setting["area_region"] = "海淀"
# 出生的公历年份
setting['year'] = "2017"
# 出生的公历月份
setting['month'] = "1"
# 出生的公历日子
setting['day'] = "11"
# 出生的公历小时
setting['hour'] = "11"
# 出生的公历分钟
setting['minute'] = "11"
# 结果产出文件名称
setting['output_fname'] = "names_girls_source_xxx.txt"

根据配置项setting[“limit_world”],系统自动来决定选用单字词典还是多字词典:

  • 如果设置了该项,比如等于“国”,那么程序会组合所有的单字为名字用于计算,比如国浩和浩国两个名字都会计算;
  • 如果不设置该项,保持空字符串,则程序只会读取*_double.txt的双字词典

程序的原理

这是一个简单的爬虫。大家可以打开http://life.httpcn.com/xingming.asp网站查看,这是一个POST表单,填写需要的参数,点提交,就会打开一个结果页面,结果页面的最下方包含了八字分数和五格分数。

如果想得到分数,就需要做两件事情,一是爬虫自动提交表单,获取结果页面;二是从结果页面提取分数;

对于第一件事情,很简单,urllib2即可实现(代码在/chinese-name-score/main/get_name_score.py):

    post_data = urllib.urlencode(params)
    req = urllib2.urlopen(sys_config.REQUEST_URL, post_data)
    content = req.read()

这里的params是个参数dict,使用这种方式,就进行了POST带数据的提交,然后从content得到了结果数据。

params的参数设定如下:

    params = {}
    
    # 日期类型,0表示公历,1表示农历
    params['data_type'] = "0"
    params['year'] = "%s" % str(user_config.setting["year"])
    params['month'] = "%s" % str(user_config.setting["month"])
    params['day'] = "%s" % str(user_config.setting["day"])
    params['hour'] = "%s" % str(user_config.setting["hour"])
    params['minute'] = "%s" % str(user_config.setting["minute"])
    params['pid'] = "%s" % str(user_config.setting["area_province"])
    params['cid'] = "%s" % str(user_config.setting["area_region"])
    # 喜用五行,0表示自动分析,1表示自定喜用神
    params['wxxy'] = "0"
    params['xing'] = "%s" % (user_config.setting["name_prefix"])
    params['ming'] = name_postfix
    # 表示女,1表示男
    if user_config.setting["sex"] == "男":
        params['sex'] = "1"
    else:
        params['sex'] = "0"
        
    params['act'] = "submit"
    params['isbz'] = "1"

第二件事情,就是从网页中提取需要的分数,我们可以使用BeautifulSoup4来实现,其语法也很简单:

    soup = BeautifulSoup(content, 'html.parser', from_encoding="GB18030")
    full_name = get_full_name(name_postfix)
    
    # print soup.find(string=re.compile(u"姓名五格评分"))
    for node in soup.find_all("div", class_="chaxun_b"):
        node_cont = node.get_text()
        if u'姓名五格评分' in node_cont:
            name_wuge = node.find(string=re.compile(u"姓名五格评分"))
            result_data['wuge_score'] = name_wuge.next_sibling.b.get_text()
        
        if u'姓名八字评分' in node_cont:
            name_wuge = node.find(string=re.compile(u"姓名八字评分"))
            result_data['bazi_score'] = name_wuge.next_sibling.b.get_text()

通过该方法,就能对HTML解析,提取八字和五格的分数。

运行结果事例

1/1287 李国锦	姓名八字评分=61.5	姓名五格评分=78.6	总分=140.1
2/1287 李国铁	姓名八字评分=61	姓名五格评分=89.7	总分=150.7
3/1287 李国晶	姓名八字评分=21	姓名五格评分=81.6	总分=102.6
4/1287 李鸣国	姓名八字评分=21	姓名五格评分=90.3	总分=111.3
5/1287 李柔国	姓名八字评分=64	姓名五格评分=78.3	总分=142.3
6/1287 李国经	姓名八字评分=21	姓名五格评分=89.8	总分=110.8
7/1287 李国蒂	姓名八字评分=22	姓名五格评分=87.2	总分=109.2
8/1287 李国登	姓名八字评分=21	姓名五格评分=81.6	总分=102.6
9/1287 李略国	姓名八字评分=21	姓名五格评分=83.7	总分=104.7
10/1287 李国添	姓名八字评分=21	姓名五格评分=81.6	总分=102.6
11/1287 李国天	姓名八字评分=22	姓名五格评分=83.7	总分=105.7
12/1287 李国田	姓名八字评分=22	姓名五格评分=93.7	总分=115.7

有了这些分数,我们就可以进行排序,是一个很实用的参考资料。

友情提示

  1. 分数跟很多因素有关,比如出生时刻、已经限定的字、限定字的笔画等因素,这些条件决定了有些名字不会分数高,不要受此影响,找出相对分数高的就可以了;
  2. 目前程序只能抓取一个网站的内容,地址是http://life.httpcn.com/xingming.asp
  3. 本列表仅供参考,看过一些文章,历史上很多名人伟人,姓名八字评分都非常低但是都建功立业,名字确实会有些影响但有时候朗朗上口就是最好的;
  4. 从本列表中选取名字之后,可以在百度、人人网等地方查查,以防有些负面的人重名、或者起这个名字的人太多了烂大街;
  5. 八字分数是中国传承,五格分数是日本人近代发明的,有时候也可以试试西方的星座起名法,并且奇怪的是八字和五个分数不同网站打分相差很大,更说明了这东西只供参考;

本文的代码已上传到github:https://github.com/peiss/chinese-name-score

附注:有些朋友不会运行程序,但是想得到宝宝起名结果列表,可以QQ693609645联系我,我帮你运行一份结果,收取少量费用

本文地址:http://crazyant.net/2076.html,转载请注明来源。

 

Firefox数据采集插件大全

本文介绍了使用firefox进行数据采集的一些小窍门、一些数据采集建议和一些优秀的用于数据采集的firefox插件。

实时操作浏览器DOM的一些注意事项

firefox的插件能够实时的对展现出来的网页进行DOM操作和查看,请注意通过firefox的firebug还有chrome的”查看元素”功能查看到的都不是页面最初的源码,而是经过浏览器的一些修改后的结果,比如浏览器会对收到的源码作清理操作,作执行javascript操作。比如对于firefox浏览器,它会自动的给table元素加上<tbody>标签。然而在数据采集时候,比如使用scrapy时,并没有经过浏览器这一步骤的处理,所以如果采集规则中带有<tbody>标签,显然会解析失败。

因此,使用firefox或者xpath做数据采集规则设计和处理时,要注意:

  • 先禁用firefox的javascript执行引擎,然后再对DOM做提取xpath的操作,这样的xpath才能用于scrapy框架中
  • 不要使用xpath的完全绝对路径,比如/html/body/div/a/href这样的,最好使用一些相对的定位方法(比如id, class, width等),或者其他的一些特性比如contains(@href, ‘image’)
  • 在你的xpath中永远不要出现<tbody>标签,除非你确定目标站有这个标签

用于数据采集的firefox插件

Firebug

地址:http://getfirebug.com/

Firebug是一个web开发者大都知道的工具,它在web采集中也非常的有用。当你鼠标移动到一个页面元素上时,firebug能够让你快速查看其html代码,这样当你构建一个元素的xpath路径时非常的有用。

20130930114533

XPather

地址:https://addons.mozilla.org/zh-CN/firefox/addon/xpather/

当你写好了一个xpath,使用该插件能够在该页面检测一下是否正确,是否能正常工作。

XPath Checker

地址:https://addons.mozilla.org/zh-CN/firefox/addon/xpath-checker/

另外一个firefox插件,能够让你在页面上检测写的xpath是否正确。

Tamper Data

地址:https://addons.mozilla.org/zh-CN/firefox/addon/tamper-data/

一个插件,能够让你修改由firefox发送的HTTP头,Firebug也能够查看HTTP头但不能修改。这个功能很强大,能直接绕过页面的javascript检测直接将参数提交给服务器。

Firecookie

地址:https://addons.mozilla.org/zh-CN/firefox/addon/firecookie/

使用Firecookie很方便的对cookie进行查看和管理,使用该插件能够创建一个新的cookie,删除已有的cookie,查看现有网站的cookie列表,管理cookie权限等很多操作。

HttpFox

地址:https://addons.mozilla.org/en-US/firefox/addon/httpfox/

对HTTP的发送、接受、参数、cookie进行查看、修改、重新发送的插件

20130930115530

Edit Cookies

地址:https://addons.mozilla.org/en-US/firefox/addon/edit-cookies/?src=search

在线更新、新增、删除cookie插件,不需要页面刷新或者修改txt文件。Edit Cookies提供了一个界面用于对cookie的操作。

20130930120232

Tamper Data

地址:https://addons.mozilla.org/en-US/firefox/addon/tamper-data/?src=search

使用tamperdata能够查看和修改浏览器的HTTP/HTTPS头和发送的POST数据。比如对HTTP的发送接收信息进行跟踪和调试,或者对提交的POST数据进行修改。

Live HTTP Headers

地址:https://addons.mozilla.org/en-US/firefox/addon/live-http-headers/?src=search

查看HTTP headers的插件

插件的选择

对于大部分静态页面来说,使用firebug、xpath、XPath Checker就能够设计一套解析规则,设计采集流程。但是对于大部分动态网站来说,很多内容都是javascript加载交互的,就需要进行HTTP头、cookie的分析,比如对于新浪微博的模拟登陆,就需要实时的监控其异步交互过程,这时就需要HttpFox、Tamper Data等插件。更特别的,有时候需要解析网站的javascript代码,可以使用webkit开元库模拟一个浏览器,来对页面做动态解析,不过性能会降低些,可以统一作权衡。

转载请注明来源:http://crazyant.net/2013/09/30/firefox%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86%E6%8F%92%E4%BB%B6%E5%A4%A7%E5%85%A8/

Python模拟登陆新浪微博并实现投票功能

上次发了一篇文章,题目叫做《Python使用cookielib和urllib2模拟登陆新浪微博并抓取数据》,里面的代码请不要怀疑,我测试过它是正确的。

新浪微博的模拟登陆,有个前提条件,你用新浪微博账号登陆的时候,新浪没有提示你输入验证码。若需要输入验证码,不好意思这里不作处理,你可以用以下几种方法解决验证码问题:
1、用图片识别软件识别,不过识别正确率会很低
2、登陆的时候如果需要验证码,我们的自己的程序就弹出验证码的图片,自己手工输入
3、外包给验证码输入公司,比如100元,把图片传过去,他给你送回文字结果10000个

程序运行到了后面,我提到urllib2里面的cookie已经存放了我们请求任何页面需要的数据,因此可以用urllib2请求任何页面、发微薄、投票实现任何事情,详细见如下代码,猥琐的分隔栏下面是新增的内容,为了方便,我把上次的代码一起贴出来了,代码注释很给力,大家可以看一看,本代码测试成功:

# coding=utf8
import urllib
import urllib2
import cookielib
import base64
import re
import json
import hashlib
import time
from django.template.defaultfilters import urlencode

# 获取一个保存cookie的对象
cj = cookielib.LWPCookieJar()
# 将一个保存cookie对象,和一个HTTP的cookie的处理器绑定
cookie_support = urllib2.HTTPCookieProcessor(cj)
# 创建一个opener,将保存了cookie的http处理器,还有设置一个handler用于处理http的URL的打开
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
# 将包含了cookie、http处理器、http的handler的资源和urllib2对象板顶在一起
urllib2.install_opener(opener)

postdata = {
    'entry': 'weibo',
    'gateway': '1',
    'from': '',
    'savestate': '7',
    'userticket': '1',
    'ssosimplelogin': '1',
    'vsnf': '1',
    'vsnval': '',
    'su': '',
    'service': 'miniblog',
    'servertime': '',
    'nonce': '',
    'pwencode': 'wsse',
    'sp': '',
    'encoding': 'UTF-8',
    'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
    'returntype': 'META'
}

def get_servertime():

    url = 'http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=dW5kZWZpbmVk&client=ssologin.js(v1.3.18)&_=1329806375939'
    data = urllib2.urlopen(url).read()
    p = re.compile('\((.*)\)')
    try:
        json_data = p.search(data).group(1)
        data = json.loads(json_data)
        servertime = str(data['servertime'])
        nonce = data['nonce']
        return servertime, nonce
    except:
        print 'Get severtime error!'
        return None

def get_pwd(pwd, servertime, nonce):
    pwd1 = hashlib.sha1(pwd).hexdigest()
    pwd2 = hashlib.sha1(pwd1).hexdigest()
    pwd3_ = pwd2 + servertime + nonce
    pwd3 = hashlib.sha1(pwd3_).hexdigest()
    return pwd3

def get_user(username):
    username_ = urllib.quote(username)
    username = base64.encodestring(username_)[:-1]
    return username

def main():
    username = 'www.crazyant.net'  # 微博账号
    pwd = 'xxx'  # 微博密码
    url = 'http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.18)'
    try:
        servertime, nonce = get_servertime()
    except:
        return
    global postdata
    postdata['servertime'] = servertime
    postdata['nonce'] = nonce
    postdata['su'] = get_user(username)
    postdata['sp'] = get_pwd(pwd, servertime, nonce)
    postdata = urllib.urlencode(postdata)
    headers = {'User-Agent':'Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0'
               , 'Referer':'http://vote.weibo.com/vid=1890981'
               }
    
    # 到此已经能够使用urllib2请求新浪任何的内容,登陆成功
    req = urllib2.Request(
        url=url,
        data=postdata,
        headers=headers
    )
    result = urllib2.urlopen(req)
    text = result.read()
    # print text
    p = re.compile('location\.replace\(\'(.*?)\'\)')
    try:
        login_url = p.search(text).group(1)
        print login_url
        # print login_url
        urllib2.urlopen(login_url)
        print "login success"
    except:
        print 'Login error!'
    # 测试读取数据,下面的URL,可以换成任意的地址,都能把内容读取下来
    #---------------------------------------------------------
    # 以下为2012年7月25日21新增:
    # 对一个投票页面进行投票
    #---------------------------------------------------------
    # 首先请求一下投票页面,这样做只是为了该页面会返回cookie,我们要保存cookie
    res = urllib2.urlopen('http://vote.weibo.com/vid=1890981')
    # 分析了投票的流程,需要如下几个参数的值
    votedata = {
              'item':'1',
              'share':'1',
              'poll_id':'1890981',
              'poll_category':'0',
              '_t':'0'
    }
    # 原文的那个headers少了一项Referer,结果导致投票不成功,所以这里加上
    headers_more = {'User-Agent':'Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0'
               , 'Referer':'http://vote.weibo.com/vid=1890981'
               }
    # 把投票的参数的值进行编码,用于urllib2请求的时候附带
    votedata = urllib.urlencode(votedata)
    # URL、数据、请求HTTP头,我们伪造了一个请求包
    req = urllib2.Request(
        url='http://vote.weibo.com/poll/joined',
        data=votedata,
        headers=headers_more
    )
    # 发出请求包,到页面看一看,投票OK
    result = urllib2.urlopen(req)
    # 把返回的内容存下来看看,其实这一步无必要了
    text = result.read()
    f = open('out.txt', 'w')
    f.write(text)
    print 'ok'
main()

 

Python使用cookielib和urllib2模拟登陆新浪微博并抓取数据

我们都知道HTTP是无连接的状态协议,但是客户端和服务器端需要保持一些相互信息,比如cookie,有了cookie,服务器才能知道刚才是这个用户登录了网站,才会给予客户端访问一些页面的权限。

用浏览器登录新浪微博,必须先登录,登陆成功后,打开其他的网页才能够访问。用程序登录新浪微博或其他验证网站,关键点也在于需要保存cookie,之后附带cookie再来访问网站,才能够达到效果。

这里就需要Python的cookielib和urllib2等的配合,将cookielib绑定到urllib2在一起,就能够在请求网页的时候附带cookie。

具体做法,首先第一步,用firefox的httpfox插件,在浏览器衷开始浏览新浪微博首页,然后登陆,从httpfox的记录中,查看每一步发送了那些数据请求了那个URL;之后再python里面,模拟这个过程,用urllib2.urlopen发送用户名密码到登陆页面,获取登陆后的cookie,之后访问其他页面,获取微博数据。

具体代码,来自豆瓣的一篇文章:地址

本人加了点注释,欢迎大家一起品尝该同学的完美代码:

 

# coding=utf8
import urllib
import urllib2
import cookielib
import base64
import re
import json
import hashlib

# 获取一个保存cookie的对象
cj = cookielib.LWPCookieJar()
# 将一个保存cookie对象,和一个HTTP的cookie的处理器绑定
cookie_support = urllib2.HTTPCookieProcessor(cj)
# 创建一个opener,将保存了cookie的http处理器,还有设置一个handler用于处理http的URL的打开
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
# 将包含了cookie、http处理器、http的handler的资源和urllib2对象板顶在一起
urllib2.install_opener(opener)

postdata = {
    'entry': 'weibo',
    'gateway': '1',
    'from': '',
    'savestate': '7',
    'userticket': '1',
    'ssosimplelogin': '1',
    'vsnf': '1',
    'vsnval': '',
    'su': '',
    'service': 'miniblog',
    'servertime': '',
    'nonce': '',
    'pwencode': 'wsse',
    'sp': '',
    'encoding': 'UTF-8',
    'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
    'returntype': 'META'
}

def get_servertime():

    url = 'http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=dW5kZWZpbmVk&client=ssologin.js(v1.3.18)&_=1329806375939'
    data = urllib2.urlopen(url).read()
    p = re.compile('\((.*)\)')
    try:
        json_data = p.search(data).group(1)
        data = json.loads(json_data)
        servertime = str(data['servertime'])
        nonce = data['nonce']
        return servertime, nonce
    except:
        print 'Get severtime error!'
        return None

def get_pwd(pwd, servertime, nonce):
    pwd1 = hashlib.sha1(pwd).hexdigest()
    pwd2 = hashlib.sha1(pwd1).hexdigest()
    pwd3_ = pwd2 + servertime + nonce
    pwd3 = hashlib.sha1(pwd3_).hexdigest()
    return pwd3

def get_user(username):
    username_ = urllib.quote(username)
    username = base64.encodestring(username_)[:-1]
    return username

def main():
    username = 'www.crazyant.net'  # 微博账号
    pwd = 'xxxx'  # 微博密码
    url = 'http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.18)'
    try:
        servertime, nonce = get_servertime()
    except:
        return
    global postdata
    postdata['servertime'] = servertime
    postdata['nonce'] = nonce
    postdata['su'] = get_user(username)
    postdata['sp'] = get_pwd(pwd, servertime, nonce)
    postdata = urllib.urlencode(postdata)
    headers = {'User-Agent':'Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0'}
    # 其实到了这里,已经能够使用urllib2请求新浪任何的内容了,这里已经登陆成功了
    req = urllib2.Request(
        url=url,
        data=postdata,
        headers=headers
    )
    result = urllib2.urlopen(req)
    text = result.read()
    # print text
    p = re.compile('location\.replace\(\'(.*?)\'\)')
    try:
        login_url = p.search(text).group(1)
        print login_url
        # print login_url
        urllib2.urlopen(login_url)
        print "login success"
    except:
        print 'Login error!'
    # 测试读取数据,下面的URL,可以换成任意的地址,都能把内容读取下来
    req = urllib2.Request(url='http://e.weibo.com/aj/mblog/mbloglist?page=1&count=15&max_id=3463810566724276&pre_page=1&end_id=3458270641877724&pagebar=1&_k=134138430655960&uid=2383944094&_t=0&__rnd=1341384513840',)
    result = urllib2.urlopen(req)
    text = result.read()
    print len(result.read())
    # unicode(eval(b),"utf-8")
    print eval("u'''" + text + "'''") 
main()

其实获取了模拟登陆后的urllib2,可以做抓数据等任何事情,你甚至可以写一个多线程的爬虫来爬遍新浪微博,我一直有这个想法,可从来没有实现。如果您有什么进展,请联系我共同进步。

PHP数据采集之使用CURL、DOMDocument和DOMXPath

这三个组件有各自独特的功能:

  • CURL能够抓取下载HTML,能模拟登陆,伪装客户端等
  • DOMDocument将下载的HTML加载成DOM
  • DOMXPath使用XPath语法进行数据的定位和采集

下面是一个具体的例子代码,抓取了本博客www.crazyant.net首页所有的超链接:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<?php
$target_url = "http://crazyant.net";
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,$target_url);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$html = curl_exec($ch);

if (!$html) {
    echo "<br />cURL error number:" .curl_errno($ch);
    echo "<br />cURL error:" . curl_error($ch);
    exit;
}
//创建一个DomDocument对象,用于处理一个HTML
$dom = new DOMDocument();
//从一个字符串加载HTML
@$dom->loadHTML($html);
//使该HTML规范化
$dom->normalize();

//用DOMXpath加载DOM,用于查询
$xpath = new DOMXPath($dom);
#获取所有的a标签的地址
$hrefs = $xpath->evaluate("/html/body//a//@href");

for ($i = 0; $i < $hrefs->length; $i++) {
    $href = $hrefs->item($i);
    $linktext = $href->nodeValue;
    echo $linktext;
    echo "<BR>";

}
?>

 

要注意点,DOMNode 类并没有getAttribute方法,所以无法根据a得到直接的属性值,这时可以用正则匹配解决,网上看到很多人直接在DOMNode 上使用了getAttribute方法竟然通过,实在是匪夷所思,如果有更好的解释,请您给我说一说,我很渴望知道怎样直接从Xpath的返回直接得到属性值。

数据采集简单示例:采集爱帮网电话号码

爱帮网单个网址:http://www.aibang.com/detail/17881112-420243957

截图:

QQ截图20120609171133

本文采集该页面的标题和2个电话号码,具体的python代码:

# -*- coding: UTF-8 -*-
'''
Created on 2012-6-9
@author: crazyant
'''

#导入urllib2库,用于获取网页
import urllib2

#使用开源库Webscraping库的xpath模块
from Webscraping import xpath,common

#首先,发送请求到爱帮网的一个页面,该页面含有地址
req = urllib2.Request('http://www.aibang.com/detail/17881112-420243957')

#获得响应
reponse = urllib2.urlopen(req)

#将响应的内容存入html变量
html = reponse.read()

#以下抓取页面的标题
title = xpath.search(html, '//div[@class="ppc_title"]/h1[1]')

print '标题:'
#这里要输出中文,因此采用common的to_unicode输出
print common.to_unicode(title[0], 'utf-8')

#使用xpath得到电话号码的节点
tel = xpath.search(html, '//dl[@class="detail_list"]/dd[@class="fb"]')

#使用正则拆分数字
import re
m = re.search(r'([\d-]+)\s([\d-]+)', tel[0])
#如果匹配,输出两个单个电话号码
print '电话号:'
if m is not None:
    for t in m.groups():
        print t

 

运行结果:

标题:
坊上人清真饭庄(高新店)
电话号:
029-88222668
029-88226458

其中主要用到了以下模块:

  • xpath:用于使用路径的方法找到节点
  • re:正则表达式模块,用于拆分电话号码(其实字符串函数也可以)
  • urllib2:用于请求指定URL的页面内容,存于字符串然后分析
  • webscraping 库的common模块:用于将获取到得中文文本转成unicode编码,这样才能够输出

数据采集技术之在Python中Libxml模块安装与使用XPath

为了使用XPath技术,对爬虫抓取的网页数据进行抽取(如标题、正文等等),之后在Windows下安装libxml2模块(安装后使用的是Libxml模块),该模块含有xpath。

准备

需要的软件包:

安装

Python2.7的安装这里不再赘述

lxml的安装,直接运行exe,会自动找到py27的目录进行安装

使用XPath抽取

下面用一个实例来验证,程序来自redice’s Blog的文章:

libxml2库的安装,xpath的使用

#coding:utf-8

import codecs
import sys
#不加如下行,无法打印Unicode字符,产生UnicodeEncodeError错误。?
sys.stdout = codecs.lookup('iso8859-1')[-1](sys.stdout)

from lxml import etree

html = r'''<div>
    <div>redice</div>
    <div id="email">redice@163.com</div>
    <div name="address">中国</div>
    <div>http://www.redicecn.com</div>
</div>'''

tree = etree.HTML(html)

#获取email。email所在的div的id为email
nodes = tree.xpath("//div[@id='email']")
print nodes[0].text

#获取地址。地址所在的div的name为address
nodes = tree.xpath("//div[@name='address']")
print nodes[0].text

#获取博客地址。博客地址位于email之后兄弟节点的第二个
nodes = tree.xpath("//div[@id='email']/following-sibling::div[2]")
print nodes[0].text

 

运行结果:

redice@163.com
中国
http://www.redicecn.com

数据采集必备知识-php计划任务的实现

站点如果做的多了,难免要发些伪原创的文章,文章的来源必然来源于网络采集,对于采集这里不详述,我自己用的是”Simple HTML DOM”,见我另一篇关于他的介绍:

数据采集利器-PHP用DOM方式处理HTML之《Simple HTML DOM》

数据采集的话,当然可以人工触发,就是每天运行一下脚本,可是这显然不是很完美,如果抓取可以自动定时获取,那么人工运行可执行页面也就省下来了。

其实php有个概念叫计划任务,可以定时运行某程序,比如数据库备份,更新缓存,生成静态页面,生成网站地图等。在采集里面的运用,就是自动采集数据,然后保存到数据库,比如每天凌晨3点运行一次。

以下是PHP用计划任务实现无人自动采集的介绍。

用到了3个函数:

1、ignore_user_abort(setting);

说明:ignore_user_abort() 函数设置与客户机断开是否会终止脚本的执行。本函数返回 user-abort 设置的之前的值(一个布尔值)。

参数:setting 可选。如果设置为 true,则忽略与用户的断开,如果设置为 false,会导致脚本停止运行。如果未设置该参数,会返回当前的设置。

2、void set_time_limit ( int $seconds )

说明:设置脚本的最大运行时间,如果时间到了,本函数会返回错误,单位是秒,默认时间是30秒。

参数:用秒计算的最大运行时间,如果为0,则代表无限时间。

注:采集的话,我们就用无限时间set_time_limit(0);

3、sleep(seconds)

说明:sleep() 函数延迟代码执行若干秒。

参数:必需。以秒计的暂停时间。

 

先给一个基本的测试程序:

//用户关闭浏览器,程序继续运行
ignore_user_abort();
//设定脚本运行无限时间
set_time_limit(0);
//每30秒执行一次 
$interval=30;
do{
	$fp = fopen('text3.txt','a');
	fwrite($fp,'test');
	fclose($fp);
	sleep($interval);
}while(true);

首先运行该程序,然后关闭该页面,程序仍然运行中,test会每隔30秒的填补到text3.txt文件。

最后根据php手册简单介绍一些相关的知识:

1、连接处理

在 PHP 内部,系统维护着连接状态,其状态有三种可能的情况:

0 – NORMAL(正常)
1 – ABORTED(异常退出)
2 – TIMEOUT(超时)

当 PHP 脚本正常地运行 NORMAL 状态时,连接为有效。当远程客户端中断连接时,ABORTED 状态的标记将会被打开。远程客户端连接的中断通常是由用户点击 STOP 按钮导致的。当连接时间超过 PHP 的时限时,TIMEOUT 状态的标记将被打开。

可以决定脚本是否需要在客户端中断连接时退出。有时候让脚本完整地运行会带来很多方便,即使没有远程浏览器接受脚本的输出。默认的情况是当远程客户端连接中断时脚本将会退出。该处理过程可由 php.ini 的 ignore_user_abort 或由 Apache .conf 设置中对应的”php_value ignore_user_abort”以及 ignore_user_abort() 函数来控制。如果没有告诉 PHP 忽略用户的中断,脚本将会被中断,除非通过 register_shutdown_function() 设置了关闭触发函数。通过该关闭触发函数,当远程用户点击 STOP 按钮后,脚本再次尝试输出数据时,PHP 将会检测到连接已被中断,并调用关闭触发函数。

脚本也有可能被内置的脚本计时器中断。默认的超时限制为 30 秒。这个值可以通过设置 php.ini 的 max_execution_time 或 Apache .conf 设置中对应的”php_value max_execution_time”参数或者 set_time_limit() 函数来更改。当计数器超时的时候,脚本将会类似于以上连接中断的情况退出,先前被注册过的关闭触发函数也将在这时被执行。在该关闭触发函数中,可以通过调用 connection_status() 函数来检查超时是否导致关闭触发函数被调用。如果超时导致了关闭触发函数的调用,该函数将返回 2。

需要注意的一点是 ABORTED 和 TIMEOUT 状态可以同时有效。这在告诉 PHP 忽略用户的退出操作时是可能的。PHP 将仍然注意用户已经中断了连接但脚本仍然在运行的情况。如果到了运行的时间限制,脚本将被退出,设置过的关闭触发函数也将被执行。在这时会发现函数 connection_status() 返回 3。

2、相关函数:

  • int ignore_user_abort ( [bool setting] )

Set whether a client disconnect should abort script execution。

Sets whether a client disconnect should cause a script to be aborted.

When running PHP as a command line script, and the script’s tty goes away without the script being terminated then the script will die the next time it tries to write anything, unless value is set to TRUE

  • int connection_aborted ( void )

Check whether client disconnected

  • int connection_status ( void )

Returns connection status bitfield

新浪微博的mid转换成base62格式的PHP函数

最近有用到将新浪微博的mid地址转换成短格式编码的方法,例如:

221110410216147026

转换后:

zF4mOFpN7A

比如新浪微博地址可以组装成这样:http://weibo.com/1642634100/5en0UftjV8H,其中数字是用户的id,后面的字符串是base62加密后的mid,因此通过组装这两个,可以得到信息的主体。

本文的代码,是由http://forum.open.weibo.com/read.php?tid=3236&uid=89934的博主的js代码改成php而来

贴下代码,运行和博主的一样,这里只是将mid转成短格式,其实逆向也很好改了:

<?php
$str62keys = array(
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
    "a", "b", "c", "d", "e", "f", "g", "h", "i", 
    "j", "k", "l", "m", "n", "o", "p", "q", 
    "r", "s", "t", "u", "v", "w", "x", "y", 
    "z","A", "B", "C", "D", "E", "F", "G", "H", 
    "I", "J", "K", "L", "M", "N", "O", "P", 
    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
);

/**
 * 10进制值转换为62进制
 * @param {String} int10 10进制值
 * @return {String} 62进制值
 */
function int10to62($int10) {
    global $str62keys;
    $s62 = '';
    $r = 0;
    while ($int10 != 0)
    {
        $r = $int10 % 62;
        $s62 = $str62keys[$r].$s62;
        $int10 = floor($int10 / 62);
    }
    return $s62;
}
/**
 * 
 * 通过mid获得短格式
 * @param string $mid
 * @return 短格式
 */
function getCodeByMid($mid){
    $url = '';
    
    for ($i = strlen($mid) - 7; $i > -7; $i -=7)    //从最后往前以7字节为一组读取mid
    {
        $offset1 = $i < 0 ? 0 : $i;
        $offset2 = $i + 7;
        $num = substr($mid, $offset1,$offset2-$offset1); 
        //mid.substring(offset1, offset2);
        
        $num = int10to62($num);
        $url = $num .$url;
    }
    
    return $url;
}

echo getCodeByMid('221110410216147026');
?>

 

为了方便,这里把那位博主的js代码也贴在这里,大家可以做一个对照:

/**
 * 新浪微博mid与url互转实用工具
 * 作者: XiNGRZ (http://weibo.com/xingrz)
 */

var WeiboUtility = {};

/**
 * 62进制字典
 */
WeiboUtility.str62keys = [
    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
    "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 
    "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", 
    "u", "v", "w", "x", "y", "z",
    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", 
    "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 
    "U", "V", "W", "X", "Y", "Z"
];

/**
 * 62进制值转换为10进制
 * @param {String} str62 62进制值
 * @return {String} 10进制值
 */
WeiboUtility.str62to10 = function(str62) {
    var i10 = 0;
    for (var i = 0; i < str62.length; i++)
    {
        var n = str62.length - i - 1;
        var s = str62[i];
        i10 += this.str62keys.indexOf(s) * Math.pow(62, n);
    }
    return i10;
};

/**
 * 10进制值转换为62进制
 * @param {String} int10 10进制值
 * @return {String} 62进制值
 */
WeiboUtility.int10to62 = function(int10) {
    var s62 = '';
    var r = 0;
    while (int10 != 0)
    {
        r = int10 % 62;
        s62 = this.str62keys[r] + s62;
        int10 = Math.floor(int10 / 62);
    }
    return s62;
};

/**
 * URL字符转换为mid
 * @param {String} url 微博URL字符,如 "wr4mOFqpbO"
 * @return {String} 微博mid,如 "201110410216293360"
 */
WeiboUtility.url2mid = function(url) {
    var mid = '';
    
    for (var i = url.length - 4; i > -4; i = i - 4)    //从最后往前以4字节为一组读取URL字符
    {
        var offset1 = i < 0 ? 0 : i;
        var offset2 = i + 4;
        var str = url.substring(offset1, offset2);
        
        str = this.str62to10(str);
        if (offset1 > 0)    //若不是第一组,则不足7位补0
        {
            while (str.length < 7)
            {
                str = '0' + str;
            }
        }
        
        mid = str + mid;
    }
    
    return mid;
};

/**
 * mid转换为URL字符
 * @param {String} mid 微博mid,如 "201110410216293360"
 * @return {String} 微博URL字符,如 "wr4mOFqpbO"
 */
WeiboUtility.mid2url = function(mid) {
    if (typeof(mid) != 'string') return false;    //mid数值较大,必须为字符串!
    
    var url = '';
    
    for (var i = mid.length - 7; i > -7; i = i - 7)    //从最后往前以7字节为一组读取mid
    {
        var offset1 = i < 0 ? 0 : i;
        var offset2 = i + 7;
        var num = mid.substring(offset1, offset2);
        
        num = this.int10to62(num);
        url = num + url;
    }
    
    return url;
};