httpclient是Apache下的一个用于执行http网络访问的一个工具包。
大致流程:新建一个httpclient对象->新建一个httpRequest对象->用httpclient去执行->得到一个response->通过解析这个response来获取自己所需要的信息。
一、新建httpClient对象:
在httpClient4.5中,初始化的方式已经和以前版本有一些不同。
有大致以下几种方式:
- static CloseableHttpClient client = HttpClients.createDefault();
- //最好使用static修饰,以保证用同一个client对象处理请求,以保存进度
- static CloseableHttpClient httpClient=HttpClients.custom().build();
此二种都是新建一个默认的httpClient对象。可以在第二种方法里添加一些网络访问选项设置。
- /**
- * initialize a instance of the httpClient depending on your own request
- */
- private static CloseableHttpClient getInstanceClient() {
- CloseableHttpClient httpClient;
- StandardHttpRequestRetryHandler standardHandler = new StandardHttpRequestRetryHandler(5, true);
- HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {
- @Override
- public boolean retryRequest(IOException arg0, int retryTimes, HttpContext arg2) {
- if (arg0 instanceof UnknownHostException || arg0 instanceof ConnectTimeoutException
- || !(arg0 instanceof SSLException) || arg0 instanceof NoHttpResponseException) {
- return true;
- }
- if (retryTimes > 5) {
- return false;
- }
- HttpClientContext clientContext = HttpClientContext.adapt(arg2);
- HttpRequest request = clientContext.getRequest();
- boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
- if (idempotent) {
- // 如果请求被认为是幂等的,那么就重试。即重复执行不影响程序其他效果的
- return true;
- }
- return false;
- }
- };
- HttpHost proxy = new HttpHost("127.0.0.1", 80);// 设置代理ip
- DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
- httpClient = HttpClients.custom().setRoutePlanner(routePlanner).setRetryHandler(handler)
- .setConnectionTimeToLive(1, TimeUnit.DAYS).setDefaultCookieStore(cookieStore).build();
- return httpClient;
- }
在该代码中分别设置了网络代理,重试处理,对于请求的keepalive时间,指定cookiestore用于保存cookie。
retryHandler:代码里给了两种方式。第一个是简便的用于设置重试,第一个参数为最大重试次数,第二个参数为请求在幂等情况下是否重试。第二种方式详细的规定了在发生了什么exception个下重试,以及幂等和重试次数下的重试情况。
routePlanner:httpClient支持代理。新建一个httphost对象传给一个routeplanner对象即可。httphost的构造方法中可以指定代理ip和端口
CookieStore:需要预先新建一个cookieStore对象。初始化方式如下:
- CookieStore cookieStore = new BasicCookieStore();
二、执行get请求:
先上代码
- /**
- * used to get the html code from the url
- */
- static RequestConfig config = RequestConfig.custom().setConnectTimeout(6000).setSocketTimeout(6000)
- .setCookieSpec(CookieSpecs.STANDARD).build(); // 设置超时及cookie策略
- public static String getDemo(String url) {
- HttpGet get = new HttpGet(url);
- get.setConfig(config);
- HttpResponse response = null;
- String html = null;
- try {
- response = client.execute(get);
- int statusCode = response.getStatusLine().getStatusCode();// 连接代码
- Header[] headers = response.getAllHeaders();
- // 用于得到返回的文件头
- for (Header header : headers) {
- System.out.println(header);
- }
- html = new String(EntityUtils.toString(response.getEntity()).getBytes("iso8859-1"), "gb2312");
- // 在后面参数输入网站的编码,一般为utf-8
- // 返回的html代码,避免发生编码错误
- System.out.println(html);
- } catch (IOException e) {
- e.printStackTrace();
- }
- return html;
- }
大致流程:新建httpget对象->用httpClient执行->解析返回的response得到自己需要的内容
cookieSpec:即cookie策略。参数为cookiespecs的一些字段。作用:1、如果网站header中有set-cookie字段时,采用默认方式可能会被cookie reject,无法写入cookie。将此属性设置成CookieSpecs.STANDARD_STRICT可避免此情况。2、如果要想忽略cookie访问,则将此属性设置成CookieSpecs.IGNORE_COOKIES。
tips:注意网站编码,否则容易出现乱码
三、执行post请求:
- /**
- * used to post form data which is the url needed
- */
- public static void postDemo(String url) {
- HttpPost post = new HttpPost(url);
- post.setConfig(config);
- post.setHeader("User-Agent",
- "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36");
- post.setHeader("Connection", "keep-alive");
- List<NameValuePair> list = new ArrayList<NameValuePair>();
- list.add(new BasicNameValuePair("key", "value"));
- list.add(new BasicNameValuePair("key", "value"));
- list.add(new BasicNameValuePair("key", "value"));
- list.add(new BasicNameValuePair("key", "value"));
- list.add(new BasicNameValuePair("key", "value"));
- try {
- HttpEntity entity = new UrlEncodedFormEntity(list, "utf-8");
- post.setEntity(entity);
- HttpResponse response = client.execute(post);
- String responseHtml = EntityUtils.toString(response.getEntity());
- System.out.println(responseHtml);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
大致流程:新建post对象->新建需要的表单页->将表单内容设置入请求中->执行并获得response
四:解析response:
得到html code:
- String responseHtml = EntityUtils.toString(response.getEntity());
得到http状态码:
- int statusCode = response.getStatusLine().getStatusCode();// 连接代码
得到response header:
- response.getFirstHeader("key");// 得到第一个名字为key的header
- response.getHeaders("key");// 得到名字为key的所有header,返回一个数组
- response.getLastHeader("key");
得到inputstream:(下载网络部分资源的时候有可能会对cookie有要求,此时需要用到httpClient来下载。)例如验证码等等。
- InputStream inputStream = response.getEntity().getContent();
五:管理cookie:
httpClient里默认自动管理cookie,如果想要提取cookie或者发送自定义的cookie,则需要在httpClient对象初始化时设置一个默认的cookiestore来保存。(方法见初始化httpClient对象里的setDefaultCookieStore)。
得到当前所有cookie:
- List<Cookie> list = cookieStore.getCookies();// get all cookies
- System.out.println("cookie is:");
- System.out.println("-----------------------");
- for (Cookie cookie : list) {
- System.out.println(cookie);
- }
- System.out.println("-----------------------");
- cookieStore.clear();
- BasicClientCookie cookie = new BasicClientCookie("name", "value");
- // new a cookie
- cookie.setDomain("domain");
- cookie.setExpiryDate(new Date());
- // set the properties of the cookie
- cookieStore.addCookie(cookie);
六:管理header:
在平常抓取过程中,经常需要在请求中加入许多header伪装成一个正常的浏览器。以免被服务器认出是爬虫而被封。
设置一些常见header:
- post.setHeader("User-Agent",
- "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36");
- post.setHeader("Connection", "keep-alive");
注意:下载某些网站的资源时,服务器会获取你的来源站,并发出对应的相应。如果来源站不对,可能会被服务器拒绝。此时只需要在请求中加个header就行。
- get1.setHeader("Referer", "http://www.a.com");
ps:
1、爬虫也要遵守基本法,在多次请求的之中为了不给对方服务器造成负担(避免被封),尽量在请求间sleep一个随机数值。
2、爬取非英文网站时注意编码格式,国内一般为utf-8,也有一些是gb2312.获取时注意转码。
3、多获得一些可靠IP(备胎),一旦自身ip被封,赶快去找备胎。附带一个简单的判断网站是否需要代理方法:
- // 判断访问目标网站是否需要代理
- private boolean isNeedProxy() {
- boolean result = true;
- URL url;
- try {
- url = new URL("http://apkpure.com/");
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setConnectTimeout(6000);
- // int i = connection.getResponseCode();
- int i = connection.getContentLength();
- if (i > 0) {
- result = false;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return result;
- }