Python 爬虫爬取指定博客的所有文章


Posted in Python onFebruary 17, 2016

自上一篇文章 Z Story : Using Django with GAE Python 后台抓取多个网站的页面全文 后,大体的进度如下:
1.增加了Cron: 用来告诉程序每隔30分钟 让一个task 醒来, 跑到指定的那几个博客上去爬取最新的更新
2.用google 的 Datastore 来存贮每次爬虫爬下来的内容。。只存贮新的内容。。

就像上次说的那样,这样以来 性能有了大幅度的提高: 原来的每次请求后, 爬虫才被唤醒 所以要花大约17秒的时间才能从后台输出到前台而现在只需要2秒不到

3.对爬虫进行了优化

1. Cron.yaml 来安排每个程序醒来的时间

经过翻文档, 问问题终于弄明白google的cron的工作原理--实际上只是google每隔指定的时间虚拟地访问一个我们自己指定的url…
因此在Django 下, 根本不需要写一个纯的python 程序 一定不要写:
if __name__=="__main__":
只需要自己配置一个url 放在views.py里:

def updatePostsDB(request):
  #deleteAll()
  SiteInfos=[]
  SiteInfo={}
  SiteInfo['PostSite']="L2ZStory"
  SiteInfo['feedurl']="feed://l2zstory.wordpress.com/feed/"
  SiteInfo['blog_type']="wordpress"
  SiteInfos.append(SiteInfo)
  SiteInfo={}
  SiteInfo['PostSite']="YukiLife"
  SiteInfo['feedurl']="feed://blog.sina.com.cn/rss/1583902832.xml"
  SiteInfo['blog_type']="sina"
  SiteInfos.append(SiteInfo)
  SiteInfo={}
  SiteInfo['PostSite']="ZLife"
  SiteInfo['feedurl']="feed://ireallife.wordpress.com/feed/"
  SiteInfo['blog_type']="wordpress"
  SiteInfos.append(SiteInfo)
  SiteInfo={}
  SiteInfo['PostSite']="ZLife_Sina"
  SiteInfo['feedurl']="feed://blog.sina.com.cn/rss/1650910587.xml"
  SiteInfo['blog_type']="sina"
  SiteInfos.append(SiteInfo)
  
  try:
    for site in SiteInfos:
      feedurl=site['feedurl']
      blog_type=site['blog_type']
      PostSite=site['PostSite']
      PostInfos=getPostInfosFromWeb(feedurl,blog_type)
      recordToDB(PostSite,PostInfos)
    Msg="Cron Job Done..." 
  except Exception,e:
    Msg=str(e)  
  return HttpResponse(Msg)

cron.yaml 要放在跟app.yaml同一个级别上:
cron:
- description: retrieve newest posts
url: /task_updatePosts/
schedule: every 30 minutes

在url.py 里只要指向这个把task_updatePostsDB 指向url就好了

调试这个cron的过程可以用惨烈来形容。。。在stackoverflow上有很多很多人在问为什么自己的cron不能工作。。。我一开始也是满头是汗,找不着头脑。。。最后侥幸弄好了,大体步骤也是空泛的很。。但是很朴实:
首先,一定要确保自己的程序没有什么syntax error….然后可以自己试着手动访问一下那个url 如果cron 正常的话,这个时候任务应该已经被执行了 最后实在不行的话多看看log…

2. Datastore的配置和利用--Using Datastore with Django

我的需求在这里很简单--没有join…所以我就直接用了最简陋的django-helper..
这个models.py 是个重点:

from appengine_django.models import BaseModel

from google.appengine.ext import db
classPostsDB(BaseModel):

    link=db.LinkProperty()

    title=db.StringProperty()

    author=db.StringProperty()

    date=db.DateTimeProperty()

    description=db.TextProperty()

    postSite=db.StringProperty()

前两行是重点中的重点。。。。我一开始天真没写第二行。。。结果我花了2个多小时都没明白是怎么回事。。得不偿失。。。
读写的时候, 千万别忘了。。。PostDB.put()

一开始的时候,我为了省事,就直接每次cron被唤醒, 就删除全部的数据, 然后重新写入新爬下来的数据。。。
结果。。。一天过后。。。有4万条读写纪录。。。。而每天免费的只有5万条。。。。
所以就改为在插入之前先看看有没有更新, 有的话就写,没的话就不写。。总算把数据库这部分搞好了。。。

3.爬虫的改进:
一开始的时候,爬虫只是去爬feed里给的文章。。这样一来,如果一个博客有24*30篇文章的话。。。最多只能拿到10篇。。。。
这次,改进版能爬所有的文章。。我分别拿孤独川陵, 韩寒, Yuki和Z的博客做的试验。。成功的很。。。其中孤独川陵那里有720+篇文章。。。无遗漏掉的被爬下来了。。

import urllib
#from BeautifulSoup import BeautifulSoup
from pyquery import PyQuery as pq
def getArticleList(url):
  lstArticles=[]
  url_prefix=url[:-6]
  Cnt=1
  
  response=urllib.urlopen(url)
  html=response.read()
  d=pq(html)
  try:
    pageCnt=d("ul.SG_pages").find('span')
    pageCnt=int(d(pageCnt).text()[1:-1])
  except:
    pageCnt=1
  for i in range(1,pageCnt+1):
    url=url_prefix+str(i)+".html"
    #print url
    response=urllib.urlopen(url)
    html=response.read()
    d=pq(html)
    title_spans=d(".atc_title").find('a')
    date_spans=d('.atc_tm')
    
    for j in range(0,len(title_spans)):
      titleObj=title_spans[j]
      dateObj=date_spans[j]
      article={}
      article['link']= d(titleObj).attr('href')
      article['title']= d(titleObj).text()
      article['date']=d(dateObj).text()
      article['desc']=getPageContent(article['link'])
      lstArticles.append(article)
  return lstArticles
  
def getPageContent(url):
  #get Page Content
  response=urllib.urlopen(url)
  html=response.read()
  d=pq(html)
  pageContent=d("div.articalContent").text()
  #print pageContent
  return pageContent
def main():
  url='http://blog.sina.com.cn/s/articlelist_1191258123_0_1.html'#Han Han
  url="http://blog.sina.com.cn/s/articlelist_1225833283_0_1.html"#Gu Du Chuan Ling
  url="http://blog.sina.com.cn/s/articlelist_1650910587_0_1.html"#Feng
  url="http://blog.sina.com.cn/s/articlelist_1583902832_0_1.html"#Yuki
  lstArticles=getArticleList(url)
  for article in lstArticles:
    f=open("blogs/"+article['date']+"_"+article['title']+".txt",'w')
    f.write(article['desc'].encode('utf-8')) #特别注意对中文的处理
    f.close()
    #print article['desc']
    
if __name__=='__main__':
  main()

对PyQuery的推荐。。
很遗憾的说, BueautifulSoup让我深深的失望了。。。在我写上篇文章的时候,当时有个小bug..一直找不到原因。。在我回家后,又搭上了很多时间试图去弄明白为什么BueautifulSoup一直不能抓到我想要的内容。。。后来大体看了看它selector部分的源代码觉得应该是它对于很多还有<script>tag的不规范html页面的解析不准确。。。

我放弃了这个库, 又试了lxml..基于xpath 很好用。。但是xpath的东西我老是需要查文档。。。所以我又找了个库PyQuery…可以用jQuery选择器的工具。。。非常非常非常好用。。。。具体的用法就看上面吧。。。这个库有前途。。。

隐忧
因为pyquery基于lxml…而lxml的底层又是c…所以估计在gae上用不了。。。我这个爬虫只能现在在我的电脑上爬好东西。。。然后push到server上。。。

总结

一句话, 我爱死Python了
两句话, 我爱死Python了,我爱死Django了
三句话, 我爱死Python了,我爱死Django了,我爱死jQuery了。。。
四句号, 我爱死Python了,我爱死Django了,我爱死jQuery了,我爱死pyQuery了。。。

Python 相关文章推荐
python求素数示例分享
Feb 16 Python
Python中类的继承代码实例
Oct 28 Python
Python3使用requests登录人人影视网站的方法
May 11 Python
教你用Python脚本快速为iOS10生成图标和截屏
Sep 22 Python
python 统计代码行数简单实例
May 04 Python
详解Python文本操作相关模块
Jun 22 Python
python模拟表单提交登录图书馆
Apr 27 Python
django 使用 request 获取浏览器发送的参数示例代码
Jun 11 Python
用Python读取几十万行文本数据
Dec 24 Python
termux中matplotlib无法显示中文问题的解决方法
Jan 11 Python
python爬虫scrapy基本使用超详细教程
Feb 20 Python
python中如何对多变量连续赋值
Jun 03 Python
Using Django with GAE Python 后台抓取多个网站的页面全文
Feb 17 #Python
python实现RSA加密(解密)算法
Feb 17 #Python
使用python实现rsa算法代码
Feb 17 #Python
Python的GUI框架PySide的安装配置教程
Feb 16 #Python
Python实现快速排序和插入排序算法及自定义排序的示例
Feb 16 #Python
python实现红包裂变算法
Feb 16 #Python
轻松实现python搭建微信公众平台
Feb 16 #Python
You might like
PHP中static关键字原理的学习研究分析
2011/07/18 PHP
PHP把JPEG图片转换成Progressive JPEG的方法
2014/06/30 PHP
php实现屏蔽掉黑帽SEO的搜索关键字
2015/04/15 PHP
JavaScript 基础篇之运算符、语句(二)
2012/04/07 Javascript
jquery动画4.升级版遮罩效果的图片走廊--带自动运行效果
2012/08/24 Javascript
用jquery实现输入框获取焦点消失文字
2013/04/27 Javascript
jquery实现效果比较好的table选中行颜色
2014/03/25 Javascript
深入理解JavaScript系列(18):面向对象编程之ECMAScript实现
2015/03/05 Javascript
javascript实现简单的分页特效
2015/08/12 Javascript
基于JS组件实现拖动滑块验证功能(代码分享)
2016/11/18 Javascript
ES6概念 Symbol toString()方法
2016/12/25 Javascript
详解React 16 中的异常处理
2017/07/28 Javascript
简单的vuex 的使用案例笔记
2018/04/13 Javascript
vue实现树形结构样式和功能的实例代码
2019/10/15 Javascript
详解vue中在循环中使用@mouseenter 和 @mouseleave事件闪烁问题解决方法
2020/04/07 Javascript
ES5 模拟 ES6 的 Symbol 实现私有成员功能示例
2020/05/06 Javascript
python OpenCV学习笔记直方图反向投影的实现
2018/02/07 Python
使用sklearn之LabelEncoder将Label标准化的方法
2018/07/11 Python
python opencv实现图片旋转矩形分割
2018/07/26 Python
详解python while 函数及while和for的区别
2018/09/07 Python
Python3的介绍、安装和命令行的认识(推荐)
2018/10/20 Python
深入了解Python枚举类型的相关知识
2019/07/09 Python
Python Django form 组件动态从数据库取choices数据实例
2020/05/19 Python
Python图像识别+KNN求解数独的实现
2020/11/13 Python
html5指南-6.如何创建离线web应用程序实现离线访问
2013/01/07 HTML / CSS
CSS3 画基本图形,圆形、椭圆形、三角形等
2016/09/20 HTML / CSS
加拿大领先的冒险和户外零售商:Atmosphere
2017/12/19 全球购物
印度尼西亚最好的小工具在线商店:Erafone.com
2019/03/26 全球购物
丽笙酒店官方网站:Radisson Hotels
2019/05/07 全球购物
北京麒麟网信息技术有限公司网络游戏测试面试题
2013/09/28 面试题
《窗前的气球》教学反思
2014/04/07 职场文书
2014个人年度工作总结
2014/12/15 职场文书
2016先进集体事迹材料范文
2016/02/25 职场文书
导游词之沈阳植物园
2019/11/30 职场文书
css3 实现文字闪烁效果的三种方式示例代码
2021/04/25 HTML / CSS
【海涛教你打DOTA】黑鸟第一视角解说
2022/04/01 DOTA