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 相关文章推荐
仅用50行Python代码实现一个简单的代理服务器
Apr 08 Python
Python中字典的基本知识初步介绍
May 21 Python
Python编写电话薄实现增删改查功能
May 07 Python
Python实现对百度云的文件上传(实例讲解)
Oct 21 Python
Python 数据处理库 pandas进阶教程
Apr 21 Python
解决python 无法加载downsample模型的问题
Oct 25 Python
python+openCV利用摄像头实现人员活动检测
Jun 22 Python
Python字典底层实现原理详解
Dec 18 Python
使用PyTorch训练一个图像分类器实例
Jan 08 Python
基于Python爬取京东双十一商品价格曲线
Oct 23 Python
python实现b站直播自动发送弹幕功能
Feb 20 Python
Python基础之数据类型知识汇总
May 18 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 中关于ord($str)&amp;gt;0x80的详细说明
2012/09/23 PHP
VIM中设置php自动缩进为4个空格的方法详解
2013/06/14 PHP
将酷狗krc歌词解析并转换为lrc歌词php源码
2014/06/20 PHP
在Mac OS的PHP环境下安装配置MemCache的全过程解析
2016/02/15 PHP
php getcwd与dirname(__FILE__)区别详解
2016/09/24 PHP
JavaScript去掉数组中的重复元素
2011/01/13 Javascript
javascript复制对象使用说明
2011/06/28 Javascript
jquery Moblie入门—hello world的示例代码学习
2013/01/08 Javascript
jquery ajax对特殊字符进行转义防止js注入使用示例
2013/11/21 Javascript
jQuery实现移动端手机商城购物车功能
2016/09/24 Javascript
百度多文件异步上传控件webuploader基本用法解析
2016/11/07 Javascript
Extjs让combobox写起来简洁又漂亮
2017/01/05 Javascript
JS判断非空至少输入两个字符的简单实现方法
2017/06/23 Javascript
js获取css的各种样式并且设置他们的方法
2017/08/22 Javascript
Sublime Text新建.vue模板并高亮(图文教程)
2017/10/26 Javascript
js实现秒表计时器
2019/12/16 Javascript
微信小程序实现签到弹窗动画
2020/09/21 Javascript
[51:17]VGJ.T vs Mineski 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python实现查询苹果手机维修进度
2015/03/16 Python
对Python中列表和数组的赋值,浅拷贝和深拷贝的实例讲解
2018/06/28 Python
python3实现名片管理系统
2020/11/29 Python
在unittest中使用 logging 模块记录测试数据的方法
2018/11/30 Python
pytorch多GPU并行运算的实现
2019/09/27 Python
Stuart Weitzman美国官网:美国奢华鞋履品牌
2016/08/18 全球购物
喜诗官方在线巧克力店:See’s Candies
2017/01/01 全球购物
Vans澳大利亚官网:购买鞋子、服装及配件
2019/09/05 全球购物
奥地利手表、香水、化妆品和珠宝购物网站:Brasty.at
2021/01/17 全球购物
工厂保洁员岗位职责
2013/12/04 职场文书
大学生个人自荐信样本
2014/03/02 职场文书
对孩子的寄语
2014/04/09 职场文书
办公室打字员岗位职责
2014/04/16 职场文书
另类冲刺标语
2014/06/24 职场文书
美术第二课堂活动总结
2014/07/08 职场文书
工程造价专业求职信
2014/07/17 职场文书
2014年秋季开学典礼致辞
2014/08/02 职场文书
银行中层干部培训心得体会
2016/01/11 职场文书