十一
12
2010
最近突然对股票很感兴趣,在学习的过程中就萌生了一个想法:“如果有一个股票短信查询系统该多好啊,发送股票代码到指定的号码,然后就能立马收到该股票实时信息”。经过一些技术调研之后,发现借助移动的139手机邮箱就可以实现该功能,一切都是免费的!
一、原理:
- 移动139邮箱提供了“用短信发邮件的功能”,使用方式:发送短信 “邮件地址[空格或#]邮件主题[空格或#]邮件正文” 到10658139。
利用此功能,我们就可以用短信,将想要查询的股票代码发送到指定的邮箱 “getstock@126.com ”中。
- 写程序,不断读取邮箱 “getstock@126.com ”中的邮件,得到股票代码和发件人邮箱地址。
- 根据股票代码,利用新浪股票查询接口,获取实时股票数据。
- 将股票数据,发送到第2步获得的发件人的邮箱中(移动会把139邮箱的邮件,自动以短信形式发送到用户手机上)。
二、使用方式:
- 开通139邮箱,并且在邮箱的设置中开启“邮件到达通知”功能,手机接收方式最好选择长短信。
- 发送短信 “getstock@126.com 600050” 到 10658139 (后台服务已开启,欢迎大家测试)
注:600050是股票代码
三、延伸:
其实,利用此原理还可以做好多有趣的事情,例如发短信获取百科数据、发短信远程操作电脑… 主要看大家的想象力了。
四、源码下载:
StockSMS.zip 代码未整理,将就查看
五、相关链接
- 139手机邮箱短信操作指令汇总
- 新浪股票查询接口
原文地址:http://www.hijava.org/code/build-stock-sms-query-system-use-139-mail
1 comment | tags: http, mail | posted in 编程实践
八
3
2010
最近老想看电影,把豆瓣和迅雷翻了个底朝天也没找到几个合适的,主要是这些网站都不提供按照评分排序的功能。于是利用周末的时间,写了个爬虫,先爬取豆瓣上的电影,然后再按照用户评分从高到低排序输出。最后会生成一个网页,如下图所示:

底层用到了之前介绍的HttpBot,生成结果网页用到了volecity,获取电影信息(评分、评价数、上映时间…)用的是正则表达式,其它就没什么特别的了。
程序还有很多不足,日后慢慢完善了…
1 comment | tags: douban, http | posted in 编程实践
八
1
2010
HttpBot 是对 java.net.HttpURLConnection类的简单封装,可以方便的获取网页内容,并且自动管理session,自动处理301重定向等。虽然不能像HttpClient那样强大,支持完整的Http协议,但却非常地灵活,可以满足我目前所有的相关需求。
获取Google首页Html代码仅需要如下两行代码即可:
1
2
| HttpBot httpBot=new HttpBot();
String html=httpBot.doGet("http://www.google.com"); |
感兴趣的可以到 http://hijava.googlecode.com/svn/HttpBot (SVN地址) 下载最新的源码。目前还太简单(200行代码),不过仍在不断维护中。
HttpBot部分源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
| package org.hijava.httpbot;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
/**
* Http网络爬虫类
*
* @author yava
*/
public class HttpBot {
private Map cookieMap;
private String userAgent;
private String encoding;
private String host;
private String referer;
private int responseCode;
private static final String separator = System.getProperty("line.separator");
private static final String GET="GET";
private static final String POST="POST";
public HttpBot() {
this.userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5";
this.encoding = "UTF-8";
cookieMap=new HashMap();
}
public HttpBot(String host,String referer){
this();
this.host=host;
this.referer=referer;
}
/**
* 以GET方式发送请求,返回页面html代码
* @param urlStr
* @return
*/
public String doGet(String urlStr) {
HttpURLConnection http=getConnection(urlStr,HttpBot.GET);
String content="";
try {
http.connect();
processCookie(http);
this.referer=urlStr;
this.responseCode=http.getResponseCode();
if(this.responseCode==302){
String location=http.getHeaderField("Location");
return doGet(location);
}
InputStream is=http.getInputStream();
content=getContent(is);
is.close();
http.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
/**
* 以Post方式发送请求,返回页面html代码
* @param urlStr
* @param paramMap 请求参数
* @return
*/
public String doPost(String urlStr,Map paramMap){
HttpURLConnection http=getConnection(urlStr,HttpBot.POST);
http.setDoOutput(true);
String content="";
try {
OutputStream os = http.getOutputStream();
os.write(getParamBytes(paramMap));
http.connect();
processCookie(http);
this.referer=urlStr;
this.responseCode=http.getResponseCode();
if(this.responseCode==302){
String location=http.getHeaderField("Location");
return doGet(location);
}
InputStream is=http.getInputStream();
content=getContent(is);
is.close();
http.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
/**
* 从输入流获取网页内容
* @param is
* @return
*/
private String getContent(InputStream is){
StringBuilder builder = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is,encoding));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append(separator);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return builder.toString();
}
private HttpURLConnection getConnection(String urlStr,String reqMethod){
HttpURLConnection http=null;
try {
URL url = new URL(urlStr);
http = (HttpURLConnection) url.openConnection();
http.setRequestProperty("User-Agent", this.userAgent);
http.setRequestProperty("Host", this.host);
http.setRequestProperty("Cookie", this.getCookie());
http.setRequestProperty("Referer", this.referer);
http.setRequestMethod(reqMethod);
http.setInstanceFollowRedirects(false);
} catch (IOException e) {
e.printStackTrace();
}
return http;
}
/**
* 处理cookie
* @param http
*/
private void processCookie(HttpURLConnection http){
String key = null;
for (int i = 1; (key = http.getHeaderFieldKey(i)) != null; i++) {
if (key.equalsIgnoreCase("set-cookie")) {
String cookie = null;
cookie = http.getHeaderField(i);
int i1=cookie.indexOf("=");
int i2=cookie.indexOf(";");
if(i1!=-1&&i2!=-1){
String _value=cookie.substring(i1+1, i2);
if("EXPIRED".equalsIgnoreCase(_value)){
continue;
}
String _key=cookie.substring(0, i1);
cookieMap.put(_key, _value);
}
}
}
}
/**
* 获取cookie
* @return
*/
public String getCookie(){
String cookie="";
for(Map.Entry entry:cookieMap.entrySet()){
cookie=cookie+entry.getKey()+"="+entry.getValue()+";";
}
return cookie;
}
private byte[] getParamBytes(Map paramMap){
String paramStr="";
for(Map.Entry entry:paramMap.entrySet()){
String value="";
try {
value=URLEncoder.encode(entry.getValue(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
paramStr=paramStr+entry.getKey()+"="+value+"&";
}
return paramStr.getBytes();
}
} |
1 comment | tags: http, httpbot | posted in 编程实践
四
6
2010
Nginx一般都是作为web服务器和反向代理服务器存在的,我们也可以把它用作一个Http代理服务器。操作很简单,只需要修改一下它的配置文件nginx.conf 添加一个Server字段。
server {
listen 8080;
location / {
proxy_pass http://$http_host$request_uri;
access_log off;
}
}
另外还需要在http字段内,用resolver指定一下DNS服务器,否则会发生 “nginx 502 bad gateway” 的错误。我采用是Google提供的DNS服务:
resolver 8.8.8.8;
修改完之后需要重启一下nginx服务器:
nginx -s reload
最后,修改一下浏览器代理设置的,访问www.ip.cn,就能看到IP地址发生变化了。

2 comments | tags: http, nginx, proxy | posted in 网站架构
四
4
2010
1、获取Squid源代码
wget ftp://ftp.cuhk.edu.hk/pub/packages/info-systems/www/squid/squid-3.1.1.tar.gz
2、编译及安装
tar -zxvf squid-3.1.1.tar.gz
cd squid-3.1.1
./configure --prefix=/usr/local/squid --enable-arp-acl --enable-linux-netfilter --enable-pthreads --enable-err-language="Simplify_Chinese" --enable-default-err-language="Simplify_Chinese" --enable-auth="basic" --enable-baisc-auth-helpers="NCSA" --enable-underscore
make
make install
3、编译生成Squid认证程序ncsa_auth
cd helpers/basic_auth/NCSA/
make
cp ncsa_auth /usr/sbin/
cd ../../../
4、使用htpasswd来生成用户名/密码对应的文件
htpasswd -c /usr/local/squid/password hijava
在输入两边密码后,一个hijava用户就生成了。如果以后需要添加用户,把上面的命令去掉-c参数再运行即可。
5、修改Squid配置文件
cd /usr/local/squid/
mv -f etc/squid.conf etc/squid.conf.bak
vi etc/squid.conf
插入如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
auth_param basic program /usr/sbin/ncsa_auth /usr/local/squid/password
acl normal proxy_auth REQUIRED
http_access allow normal
# Deny requests to certain unsafe ports
http_access deny !Safe_ports
# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports
# And finally deny all other access to this proxy
http_access deny all
# Squid normally listens to port 3128
http_port 3128
# We recommend you to use at least the following line.
hierarchy_stoplist cgi-bin ?
# Uncomment and adjust the following to add a disk cache directory.
#cache_dir null /tmp
# Leave coredumps in the first cache dir
coredump_dir /usr/local/squid/var/cache
# Add any of your own refresh_pattern entries above these.
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320 |
6、启动Squid
./sbin/squid
参考:http://wiki.ubuntu.org.cn/Squid%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3
no comments | tags: http, squid, ubuntu | posted in 系统工具
二
21
2010
今天读了一篇不错的文章What really happens when you navigate to a URL ,作者用示例形象地描述了浏览器与服务器的整个交互过程。
- 在浏览器里输入网址
- 浏览器查找服务器的IP地址(浏览器缓存 -> 操作系统缓存 -> 路由器缓存 -> DNS服务器 )
- 浏览器向WEB服务器发出HTTP请求
- 服务器处理请求(ASP,JSP,PHP…解析器解析)
- 服务器返回响应的HTML代码
- 浏览器开始解析渲染HTML
- 于此同时,浏览器对于碰到的嵌入在HTML里的对象发起HTTP请求(Images,CSS,JS)
这只是一个大体流程,每一个环节都可以延伸出很多技术来,像CDN,Http Protocol,DNS… 需要每一个WEB开发人员去深入钻研。
中文翻译:http://article.yeeyan.org/view/54517/91367
no comments | tags: browser, http, url | posted in 网络资源
二
22
2009
no comments | tags: http, idea | posted in 编程实践
十一
20
2008
LiveHTTPHeaders是FireFox下的一个插件,可以用来实时监测发起的http请求和响应,也可以修改请求参数之后重新发起请求。
以前一直使用Visual Sniffer作为检测工具,不过经常遇到乱码的情况。最重要的是,LiveHTTPHeaders能在修改参数之后重新发起请求,以浏览器插件提供,更便于随时查看http请求。
LiveHTTPHeaders官网:http://livehttpheaders.mozdev.org/
no comments | tags: firefox, http, plugin | posted in 系统工具
十一
17
2008
但我们使用HttpURLConnection访问web页面的时候不免要涉及到cookie处理,下面简要的介绍一下如何获取和发送相关的cookie
1
2
3
4
5
6
7
8
9
| String cookieVal = null;
String key=null;
for (int i = 1; (key = http.getHeaderFieldKey(i)) != null; i++ ) {
if (key.equalsIgnoreCase("set-cookie")) {
cookieVal = http.getHeaderField(i);
cookieVal = cookieVal.substring(0, cookieVal.indexOf(";"));
sessionId=sessionId+cookieVal+";";
}
} |
其中sessionId就是获取到的cookie,当我们访问需要授权的页面时,将cookie写入到http请求的头部就可以了。如下所示:
1
| http.setRequestProperty("Cookie", sessionId); |
no comments | tags: cookie, http | posted in 编程实践
九
15
2008
问题分析
不过在实际使用中, 还是发现按照最基本的方式调用 HttpClient 时, 并不支持 UTF-8 编码, 在网络上找过一些文章, 也不得要领, 于是查看了 commons-httpclient-3.0.1 的一些代码, 首先在 PostMethod 中找到了 generateRequestEntity() 方法:
/**
* Generates a request entity from the post parameters, if present. Calls
* {@link EntityEnclosingMethod#generateRequestBody()} if parameters have not been set.
*
* @since 3.0
*/
protected RequestEntity generateRequestEntity() {
if (!this.params.isEmpty()) {
// Use a ByteArrayRequestEntity instead of a StringRequestEntity.
// This is to avoid potential encoding issues. Form url encoded strings
// are ASCII by definition but the content type may not be. Treating the content
// as bytes allows us to keep the current charset without worrying about how
// this charset will effect the encoding of the form url encoded string.
String content = EncodingUtil.formUrlEncode(getParameters(), getRequestCharSet());
ByteArrayRequestEntity entity = new ByteArrayRequestEntity(
EncodingUtil.getAsciiBytes(content),
FORM_URL_ENCODED_CONTENT_TYPE
);
return entity;
} else {
return super.generateRequestEntity();
}
} |
原来使用 NameValuePair 加入的 HTTP 请求的参数最终都会转化为 RequestEntity 提交到 HTTP 服务器, 接着在 PostMethod 的父类 EntityEnclosingMethod 中找到了如下的代码:
/**
* Returns the request's charset. The charset is parsed from the request entity's
* content type, unless the content type header has been set manually.
*
* @see RequestEntity#getContentType()
*
* @since 3.0
*/
public String getRequestCharSet() {
if (getRequestHeader("Content-Type") == null) {
// check the content type from request entity
// We can't call getRequestEntity() since it will probably call
// this method.
if (this.requestEntity != null) {
return getContentCharSet(
new Header("Content-Type", requestEntity.getContentType()));
} else {
return super.getRequestCharSet();
}
} else {
return super.getRequestCharSet();
}
} |
解决方案
从上面两段代码可以看出是 HttpClient 是如何依据 “Content-Type” 获得请求的编码(字符集), 而这个编码又是如何应用到提交内容的编码过程中去的. 按照这个原来, 其实我们只需要重载 getRequestCharSet() 方法, 返回我们需要的编码(字符集)名称, 就可以解决 UTF-8 或者其它非默认编码提交 POST 请求时的乱码问题了.
测试
首先在 Tomcat 的 ROOT WebApp 下部署一个页面 test.jsp, 作为测试页面, 主要代码片段如下:
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page session="false" %>
<%
request.setCharacterEncoding("UTF-8");
String val = request.getParameter("TEXT");
System.out.println(">>>> The result is " + val);
%> |
接着写一个测试类, 主要代码如下:
public static void main(String[] args) throws Exception, IOException {
String url = "http://localhost:8080/test.jsp";
PostMethod postMethod = new UTF8PostMethod(url);
//填入各个表单域的值
NameValuePair[] data = {
new NameValuePair("TEXT", "中文"),
};
//将表单的值放入postMethod中
postMethod.setRequestBody(data);
//执行postMethod
HttpClient httpClient = new HttpClient();
httpClient.executeMethod(postMethod);
}
//Inner class for UTF-8 support
public static class UTF8PostMethod extends PostMethod{
public UTF8PostMethod(String url){
super(url);
}
@Override
public String getRequestCharSet() {
//return super.getRequestCharSet();
return "UTF-8";
}
} |
运行这个测试程序, 在 Tomcat 的后台输出中可以正确打印出 “>>>> The result is 中文” .
转自:http://thinkbase.net/w/main/Wiki?action=action_search&text=%22HttpClient+POST+%E7%9A%84+UTF-8+%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98%22
no comments | tags: http, HttpClient | posted in 编程实践