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 相关文章推荐
在Python3中使用asyncio库进行快速数据抓取的教程
Apr 02 Python
python线程池(threadpool)模块使用笔记详解
Nov 17 Python
Python中property属性实例解析
Feb 10 Python
Python用csv写入文件_消除空余行的方法
Jul 06 Python
python实现图片压缩代码实例
Aug 12 Python
在pycharm中显示python画的图方法
Aug 31 Python
关于numpy中eye和identity的区别详解
Nov 29 Python
python 视频逐帧保存为图片的完整实例
Dec 10 Python
tensorflow使用CNN分析mnist手写体数字数据集
Jun 17 Python
详解python3类型注释annotations实用案例
Jan 20 Python
python实现MySQL指定表增量同步数据到clickhouse的脚本
Feb 26 Python
Python爬虫爬取全球疫情数据并存储到mysql数据库的步骤
Mar 29 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
模板引擎正则表达式调试小技巧
2011/07/20 PHP
easyui的tabs update正确用法分享
2014/03/21 PHP
PHP魔术方法__GET、__SET使用实例
2014/11/25 PHP
10个简化PHP开发的工具
2014/12/25 PHP
js 页面元素的几个用法总结
2013/11/18 Javascript
js中this的用法实例分析
2015/01/10 Javascript
JS打字效果的动态菜单代码分享
2015/08/21 Javascript
详解js的事件代理(委托)
2016/12/22 Javascript
JQueryEasyUI框架下的combobox的取值和绑定的方法
2017/01/22 Javascript
jQuery.cookie.js使用方法及相关参数解释
2017/03/06 Javascript
基于vue2.0+vuex的日期选择组件功能实现
2017/03/13 Javascript
backbone简介_动力节点Java学院整理
2017/07/14 Javascript
详解JSON.stringify()的5个秘密特性
2020/05/26 Javascript
jQuery插件实现图片轮播效果
2020/10/19 jQuery
React实现todolist功能
2020/12/28 Javascript
Python群发邮件实例代码
2014/01/03 Python
python3制作捧腹网段子页爬虫
2017/02/12 Python
VTK与Python实现机械臂三维模型可视化详解
2017/12/13 Python
python实现批量修改图片格式和尺寸
2018/06/07 Python
用vue.js组件模拟v-model指令实例方法
2019/07/05 Python
python-序列解包(对可迭代元素的快速取值方法)
2019/08/24 Python
Python基于内置库pytesseract实现图片验证码识别功能
2020/02/24 Python
纯CSS3单页切换导航菜单界面设计的简单实现
2016/08/16 HTML / CSS
网站域名和主机:Domain.com
2019/04/01 全球购物
c++工程师面试问题
2013/08/04 面试题
手工社团活动方案
2014/02/17 职场文书
个人总结与自我评价
2014/09/18 职场文书
党委干部批评与自我批评发言稿
2014/09/28 职场文书
批评与自我批评总结
2014/10/17 职场文书
公司离职证明范本
2014/10/17 职场文书
2014年手术室工作总结
2014/11/26 职场文书
幼儿园亲子活动感想
2015/08/07 职场文书
使用CSS实现小三角边框原理解析
2021/11/07 HTML / CSS
CSS三大特性继承性、层叠性和优先级详解
2022/01/18 HTML / CSS
方法汇总:Python 安装第三方库常用
2022/04/26 Python
Redis实现短信验证码登录的示例代码
2022/06/14 Redis