并发爬虫小练习。

直接粘贴到本地,命名为.py文件即可运行,运行时的参数为你想要爬取的用户。默认是本博客。

输出是以用户名命名的目录,目录内便是博客内容。

仅供学习python的多线程编程方法,后续会重写成并行爬虫。

爬虫代码如下:

  1. # -*- coding:utf-8 -*-
  2. from multiprocessing.managers import BaseManager
  3. from pyquery import PyQuery
  4. import os, sys, urllib
  5. import re, random, logging, time
  6. import Queue, threading, multiprocessing, threadpool
  7.  
  8. USER_NAME = 'kirai'
  9. TOTAL_PAGE_NUMBER = 0
  10. INT_REGEXP = re.compile('([\d]+)')
  11. BASE_URL = 'http://www.cnblogs.com/'+USER_NAME+'/p/?page='
  12. ARTICLE_REGEXP = re.compile('href=\"(http://www.cnblogs.com/'+USER_NAME+'/p/[\d]+.html)\"')
  13. THREAD_NUMBER = multiprocessing.cpu_count() * 2
  14. ARTICLE_URLS_MUTEX = threading.Lock()
  15. ARTICLE_URLS = []
  16.  
  17. class ListWithLinkExtend(list):
  18. def extend(self, value):
  19. super(ListWithLinkExtend, self).extend(value)
  20. return self
  21.  
  22. def get_total_page_number():
  23. doc = PyQuery(url=BASE_URL)
  24. return int(INT_REGEXP.findall(
  25. doc.find('.pager .Pager').text())[0].encode('ascii'))
  26.  
  27. def get_page_url():
  28. global TOTAL_PAGE_NUMBER
  29. return map(lambda page: BASE_URL+str(page),
  30. [i for i in range(1, TOTAL_PAGE_NUMBER+1)])
  31.  
  32. def get_article_url(idx):
  33. url = PAGE_URLS[idx]
  34. doc = PyQuery(url=url)
  35. article_urls = ARTICLE_REGEXP.findall(str(doc.find('.PostList .postTitl2')))
  36. return article_urls
  37.  
  38. def handle_result(request, result):
  39. global ARTICLE_URLS_MUTEX, ARTICLE_URLS
  40. try:
  41. ARTICLE_URLS_MUTEX.acquire()
  42. ARTICLE_URLS.append(result)
  43. finally:
  44. ARTICLE_URLS_MUTEX.release()
  45.  
  46. def cluster_process():
  47. global ARTICLE_URLS
  48. # list : urls
  49. task_queue = Queue.Queue()
  50. # str : path
  51. result_queue = Queue.Queue()
  52. KiraiManager.register('get_task_queue', callable=lambda: task_queue)
  53. KiraiManager.register('get_result_queue', callable=lambda: result_queue)
  54. manager = KiraiManager(address=('', 6969), authkey='whosyourdaddy')
  55. manager.start()
  56. manager.shutdown()
  57. # article_flag, article_urls = get_article_url()
  58.  
  59. # a simple way.
  60. def get_article(url):
  61. html = urllib.urlopen(url).read()
  62. return html, INT_REGEXP.findall(url)[0]
  63.  
  64. def save_article(request, result):
  65. content = result[0]
  66. file_name = result[1]
  67. path = './' + USER_NAME + '/' + file_name + '.html'
  68. try:
  69. fp = file(path, 'w')
  70. fp.writelines(content)
  71. finally:
  72. fp.close()
  73.  
  74. def thread_process():
  75. global ARTICLE_URLS
  76. os.mkdir(USER_NAME)
  77. thread_pool = threadpool.ThreadPool(THREAD_NUMBER)
  78. requests = threadpool.makeRequests(get_article, ARTICLE_URLS, save_article)
  79. [thread_pool.putRequest(req) for req in requests]
  80. thread_pool.wait()
  81.  
  82. def __main__(argv):
  83. global ARTICLE_URLS, TOTAL_PAGE_NUMBER, USER_NAME, BASE_URL, ARTICLE_REGEXP, PAGE_URLS, TOTAL_PAGE_NUMBER
  84. if len(argv) == 2:
  85. USER_NAME = argv[1]
  86. BASE_URL = 'http://www.cnblogs.com/'+USER_NAME+'/p/?page='
  87. ARTICLE_REGEXP = re.compile('href=\"(http://www.cnblogs.com/'+USER_NAME+'/p/[\d]+.html)\"')
  88. TOTAL_PAGE_NUMBER = get_total_page_number()
  89. PAGE_URLS = get_page_url()
  90. thread_pool = threadpool.ThreadPool(THREAD_NUMBER)
  91. requests = threadpool.makeRequests(
  92. get_article_url,
  93. [i for i in range(0, TOTAL_PAGE_NUMBER)],
  94. handle_result)
  95. [thread_pool.putRequest(req) for req in requests]
  96. thread_pool.wait()
  97. ARTICLE_URLS = list(reduce(lambda a, b: ListWithLinkExtend(a).extend(ListWithLinkExtend(b)),
  98. ARTICLE_URLS))
  99. thread_process()
  100.  
  101. if __name__ == '__main__':
  102. __main__(sys.argv)

简单介绍下全局变量的意义:

USER_NAME:希望爬取的用户名,默认为kirai。

TOTAL_PAGE_NUMBER:会被更新成博客随笔的总页数。

INT_REGEXP:为了匹配数字的正则。
BASE_URL:随笔页的初始URL。

ARTICLE_REGEXP:在经过pyquery处理过后的每个随笔目录页中提取出博客文章页面的正则。

THREAD_NUMBER:线程数,默认设置是本机cpu核数的2倍。

ARTICLE_URLS_MUTEX:ARTICLE_URLS的锁,保证线程唯一占用。

ARTICLE_URLS:用于存放所有的文章url。

[Python爬虫]cnblogs博客备份工具(可扩展成并行)的更多相关文章

  1. 推荐一款自己的软件作品[豆约翰博客备份专家],新浪博客,QQ空间,CSDN,cnblogs博客备份,导出CHM,PDF(转载)

    推荐一款自己的软件作品[豆约翰博客备份专 豆约翰博客备份专家是完全免费,功能强大的博客备份工具,博客电子书(PDF,CHM和TXT)生成工具,博文离线浏览工具,软件界面美观大方,支持多个主流博客网站( ...

  2. cnblogs博客迁移到hexo

    cnblogs博客备份 备份地址:https://i.cnblogs.com/BlogBackup.aspx?type=1 备份文件为xml格式,打开备份文件,如下所示: <?xml versi ...

  3. 用Python编写博客导出工具

    用Python编写博客导出工具 罗朝辉 (http://kesalin.github.io/) CC 许可,转载请注明出处   写在前面的话 我在 github 上用 octopress 搭建了个人博 ...

  4. python编写的自动获取代理IP列表的爬虫-chinaboywg-ChinaUnix博客

    python编写的自动获取代理IP列表的爬虫-chinaboywg-ChinaUnix博客 undefined Python多线程抓取代理服务器 | Linux运维笔记 undefined java如 ...

  5. python爬取博客圆首页文章链接+标题

    新人一枚,初来乍到,请多关照 来到博客园,不知道写点啥,那就去瞄一瞄大家都在干什么好了. 使用python 爬取博客园首页文章链接和标题. 首先当然是环境了,爬虫在window10系统下,python ...

  6. BlogPublishTool - 博客发布工具

    BlogPublishTool - 博客发布工具 这是一个发布博客的工具.本博客使用本工具发布. 本工具源码已上传至github:https://github.com/ChildishChange/B ...

  7. org-mode 写 cnblogs 博客

    1. 为什么用org-mode写博客 我最开始用Emacs, 是因为org-mode.这是一个专注于写,而让我忽略展示结果的一种写作方式.为 什么这么说?因为所有内容的格式都是可定制的.按照自己喜欢的 ...

  8. 有哪些关于 Python 的技术博客?

    Python是一种动态解释型的编程语言,它可以在Windows.UNIX.MAC等多种操作系统以及Java..NET开发平台上使用.不过包含的内容很多,加上各种标准库.拓展库,乱花渐欲迷人眼.因此如何 ...

  9. 把cnblogs变成简书 - cnblogs博客自定义皮肤css样式

    吐槽 博客园cnblogs作为老牌的IT技术博客类网站,为广大的开发者提供了非常不错的学习交流平台. 虽然博客内容才是重点,但是如果有赏心悦目的页面不更好吗! cnblogs可以更换博客模板,并且提供 ...

随机推荐

  1. WPF 打开文件、文件夹

    打开文件代码: OpenFileDialog openFileDialog = new OpenFileDialog();            openFileDialog.Title = &quo ...

  2. 理解Bitcode

    用Xcode 7 beta 3在真机(iOS 8.3)上运行一下我们的工程,结果发现工程编译不过.看了下问题,报的是以下错误: 1 ld: ‘/Users/**/Framework/SDKs/Poly ...

  3. 解决32位plsql连接数据库的问题

    解决32位plsql连接数据库的问题:   安装32位的oracle数据库client版,此地址可下载[http://www.oracle.com/technetwork/database/featu ...

  4. What is the difference between a Clustered and Non Clustered Index?

    A clustered index determines the order in which the rows of a table are stored on disk. If a table h ...

  5. 协程并发框架gevent及其用法

    gevent是python的一个并发框架,采用协程实现并发目的,用起来也非常简单 gevent的docs:http://www.gevent.org/contents.html 一个最简单的例子: i ...

  6. Fiddler- -Composer创建和发送HTTP Request

    Fiddler的功能还有很多, 很多功能都没有被挖掘出来.这次我们介绍Fiddler中的一个非常有用的功能Composer,是用来创建和发送HTTP Request的.Composer的使用方法很简单 ...

  7. jq 页面延时刷新

    最常用的方法 <script language='javascript' type='text/javascript'> $(function () { setTimeout(functi ...

  8. leetcode 257

    查找二叉树中根节点到叶子节点的所有路径: 本题有两种解法:递归解法和非递归解法,递归解法请参考:http://blog.csdn.net/booirror/article/details/477331 ...

  9. 游戏制作之路:游戏引擎选择、Mac下和Windows下UnrealEngine 4体验对比、文档及其他

    UnrealEngine 4和Unity3d的选择 订阅了UrealEngine4(UE4)开发者.我开始做网站用的是ASP.NET和C#,之后做网站虽然换用更方便的PHP(因为做的都是小网站).我想 ...

  10. 结合WebSocket编写WebGL综合场景示例

    在WebGL场景中导入多个Babylon骨骼模型,在局域网用WebSocket实现多用户交互控制. 首先是场景截图: 上图在场景中导入一个Babylon骨骼模型,使用asdw.空格.鼠标控制加速度移动 ...