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获取文件ssdeep值的方法
Oct 05 Python
python实现用于测试网站访问速率的方法
May 26 Python
python实现自动重启本程序的方法
Jul 09 Python
python实现Zabbix-API监控
Sep 17 Python
使用Python处理BAM的方法
Sep 28 Python
详解配置Django的Celery异步之路踩坑
Nov 25 Python
Python字符编码转码之GBK,UTF8互转
Feb 09 Python
python 图像判断,清晰度(明暗),彩色与黑白实例
Jun 04 Python
在python下实现word2vec词向量训练与加载实例
Jun 09 Python
python怎么对数字进行过滤
Jul 05 Python
python爬虫数据保存到mongoDB的实例方法
Jul 28 Python
Anaconda安装pytorch和paddle的方法步骤
Apr 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使用session二维数组实例
2014/11/06 PHP
PHP中文竖排转换实现方法
2015/10/23 PHP
深入理解PHP内核(二)之SAPI探究
2015/11/10 PHP
php简单备份与还原MySql的方法
2016/05/09 PHP
php监测数据是否成功插入到Mysql数据库的方法
2016/11/25 PHP
YII2.0框架行为(Behavior)深入详解
2019/07/26 PHP
基于jquery的横向滚动条(滑动条)
2011/02/24 Javascript
打豆豆小游戏 用javascript编写的[打豆豆]小游戏
2013/01/08 Javascript
jquery实现鼠标经过显示下划线的渐变下拉菜单效果代码
2015/08/24 Javascript
JS实现的表头列头固定页面功能示例
2017/01/10 Javascript
angular forEach方法遍历源码解读
2017/01/25 Javascript
从零开始学习Node.js系列教程三:图片上传和显示方法示例
2017/04/13 Javascript
Angular4实现动态添加删除表单输入框功能
2017/08/11 Javascript
JavaScript实现数值自动增加动画
2017/12/28 Javascript
js实现HTML中Select二级联动的实例
2018/01/05 Javascript
详解简单易懂的 ES6 Iterators 指南和示例
2019/09/24 Javascript
原生JavaScript实现刮刮乐
2020/09/29 Javascript
在Python的Django框架中显示对象子集的方法
2015/07/21 Python
Python数据结构之双向链表的定义与使用方法示例
2018/01/16 Python
python中实现字符串翻转的方法
2018/07/11 Python
Python利用requests模块下载图片实例代码
2019/08/12 Python
Python之Class&amp;Object用法详解
2019/12/25 Python
彻底弄明白CSS3的Media Queries(跨平台设计)
2010/07/27 HTML / CSS
html5 初试 indexedDB(推荐)
2016/07/21 HTML / CSS
自荐信格式技巧有哪些呢
2013/11/19 职场文书
工业自动化毕业生自荐信范文
2014/01/04 职场文书
绩效考核实施方案
2014/03/18 职场文书
走群众路线剖析材料
2014/10/09 职场文书
出纳试用期自我评价
2015/03/10 职场文书
大学生心理健康活动总结
2015/05/08 职场文书
预备党员考察意见范文
2015/06/01 职场文书
六一活动主持词
2015/06/30 职场文书
开学第一天的感想
2015/08/10 职场文书
保险公司增员口号
2015/12/25 职场文书
Matplotlib绘制混淆矩阵的实现
2021/05/27 Python
浅谈Python中的正则表达式
2021/06/28 Python