在前面的自动发带图的微博博文中讲述了怎样编写脚本,通过新浪微博的API发送带图的微博。今天这篇博文讲述怎样抓取信息定时发表到微博。其中用到的信息抓取有如下两种方式:
- 通过开放API抓取笑话信息发布到微博
- 使用BS4解析html页面提取信息发布到微博
通过API获取信息
现在开放的免费API有很多,有时候不得不感叹现在是一个API的世界,API就像是一个标准的资源供应者及资源控制器。大家可以到这里来挑选自己需要的API服务。
本实践中选用的是一个免费的笑话API接口,其接口及调用信息如下:
其中的apikey需要注册一个百度应用,很简单,这里就不再赘述了。本实践的目标是获取一个笑话列表,列表的每个元素包含笑话正文和笑话更新时间。流程就是:构造请求 -> 发送请求 -> 获得返回的json数据 -> 解析json数据提取自己需要的信息。具体代码如下
import json, requests
def get_jokes():
API_KEY="填写你的"
url = 'http://apis.baidu.com/showapi_open_bus/showapi_joke/joke_text?page=1'
#将apikey这个参数写进请求的header中
headers = {"apikey":API_KEY}
r = requests.get(url,headers=headers,verify=False)
jokes=[]
content = r.text
if(content):
#print type(content)
js_cont = json.loads(content)
for i in js_cont['showapi_res_body']['contentlist']:
jokes.append((i['text'],i['ct']))
return jokes
for i,item in enumerate(get_jokes()):
print "第%d条笑话:%s" %(i,item[0]),
print "更新时间为:%s" %item[1]
将返回的信息构造成文本通过前文中的方法通过微博的文本API发送出去就行了。
抓取「ONE · 一个」首页并提取信息
「ONE · 一个」的网站首页会每日更新一张图片和一段话,本实践就是抓取它的首页,使用BS4提取我们需要的信息。抓取的目标信息有以下几项:
- 每日更新的图片URL
- 每日更新的那句话
- 图片名称及作者
- VOL以及时间
首先来查看一下我们需要的信息在网页源码中的形式:
具体代码如下:
def get_one_info():
"""抓取ONE-APP网页并提取信息"""
from bs4 import BeautifulSoup
URL_ONE ="http://wufazhuce.com/"
r = requests.get(URL_ONE,verify=False)
html = r.text
soup = BeautifulSoup(html,"html.parser")
info ={}#将提取的信息存储到一个字典中
for i in soup.find_all("div","item active"):
#提取图片url
info["pic_url"]=i.img["src"]
for j in i.find_all("a"):
#提取每天更新的那段话及作者
info["text"]=j.string
info["date"]=[]
for j in i.find_all("p"):
#提取VOL、年月日时间
info["date"].append(j.string)
for j in i.find_all("div","fp-one-imagen-footer"):
#提取图片名称及作者
info["pic_info"]=j.string.strip()
return info
将获取的信息定时并发布到微博
既然想要定时发表微博,总不能让程序在自己的电脑上跑一天24H不关机吧,所以需要找一个托管平台。目前,我手里有两个平台的资源可以使用:
- 新浪云平台SAE
- 腾讯云Tencent Cloud
SAE部署
在SAE上通过cron做定时的任务本质上是定时发起一个http请求。这就需要将代码转换成一个http访问接口的形式。由于一个SAE的一个cron任务有一定的时间限制(本质是一个http请求有时间限制),而我们信息抽取不一定在它的限制时间内做完,所以我没有选择把程序部署到SAE上。如果想尝试的话,可以参考这两个文档
腾讯云部署
腾讯云服务器相当于一个24H不关机的虚拟主机。你可以在上面安装自己熟悉的操作系统,通过SSH远程登录进行操作。我选用的是Ubuntu这个Linux发行版。可以在上面做cron定时任务,但这样一个简单的应用,我只是简单的做了一下处理,让程序一直在后台运行,每执行一次任务,就休眠24小时:time.sleep(24*60*60)
。
部署在腾讯云上的完整脚本如下:
#!/usr/bin/env python
# encoding: utf-8
# file:post_weibo.py
import requests, json,time
def post_weibo(weibo_text,pic_uri = None):
"""发表微博"""
url_post_a_text = "https://api.weibo.com/2/statuses/update.json"
url_post_a_pic = "https://upload.api.weibo.com/2/statuses/upload.json"
ACCESS_TOKEN = "填写你的授权token"
playload = {
"access_token":ACCESS_TOKEN,
"status":unicode(weibo_text)
}
if pic_uri == None:
r = requests.post(url_post_a_text,data = playload,verify=False)
# print r.text
else:
files={"pic":open(pic_uri,"rb")}
r = requests.post(url_post_a_pic,data=playload,files = files,verify=False)
# print r.text
#print r.text
def get_jokes():
"""获得笑话"""
API_KEY="填写你的百度APIKEY"
url = 'http://apis.baidu.com/showapi_open_bus/showapi_joke/joke_text?page=1'
headers = {"apikey":API_KEY}
r = requests.get(url,headers=headers,verify=False)
jokes=[]
#import sys, urllib, urllib2
# req = urllib2.Request(url)
# req.add_header("apikey", API_KEY)
# resp = urllib2.urlopen(req)
# content = resp.read()
content = r.text
if(content):
print type(content)
js_cont = json.loads(content)
for i in js_cont['showapi_res_body']['contentlist']:
jokes.append((i['text'],i['ct']))
return jokes
def get_one_info():
"""抓取ONE-APP网页并提取信息"""
from bs4 import BeautifulSoup
URL_ONE ="http://wufazhuce.com/"
r = requests.get(URL_ONE,verify=False)
html = r.text
soup = BeautifulSoup(html,"html.parser")
info ={}
for i in soup.find_all("div","item active"):
info["pic_url"]=i.img["src"]
for j in i.find_all("a"):
info["text"]=j.string
info["date"]=[]
for j in i.find_all("p"):
info["date"].append(j.string)
for j in i.find_all("div","fp-one-imagen-footer"):
info["pic_info"]=j.string.strip()
return info
if __name__ == "__main__":
import time
while(True):
#发表从ONE-APP网站抓取提取的信息
try:
info = get_one_info()
pic_name = "pic.jpg"
web_text = info["text"]+info["date"][1]+u","+info["date"][2]+u"[图]"+info["pic_info"]
with open(pic_name,"a") as pic:
# 由于直接通过图片url的形式发表微博的API接口需要申请
# 所以选择先把图片保存成图片文件再发布
# 当然也可以使用StringIO不保存直接编码进POST请求
pic.write(requests.get(info["pic_url"],verify=False).content)
post_weibo(weibo_text=web_text,pic_uri=pic_name)
print "Done"
# time.sleep(10)
except Exception, e:
print e
#发表通过API接口获取的笑话信息
try:
jokes = get_jokes()
for i in jokes:
post_weibo(i[0])
time.sleep(2)
except Exception,e:
print e
# 每次执行完上面的任务,延时一天
time.sleep(24*60*60)
注:关闭SSH端口,要使程序不停止运行,使用以下命令运行脚本$python post_weibo.py&