Apache HttpComponents中的cookie匹配策略
Apache HttpComponents中的cookie匹配策略
*/-->
pre.src {background-color: #292b2e; color: #b2b2b2;}
pre.src {background-color: #292b2e; color: #b2b2b2;}
pre.src {background-color: #292b2e; color: #b2b2b2;}
pre.src {background-color: #292b2e; color: #b2b2b2;}
pre.src {background-color: #292b2e; color: #b2b2b2;}
pre.src {background-color: #292b2e; color: #b2b2b2;}
Apache HttpComponents中的cookie匹配策略
1 简介
在clojure中使用clj-http抓取网页时,需要提交自定义cookie,总是不能成功发送,研究一下HttpClient中Cookie的工作方式。
clj-http包装了HttpClient库,对于请求页面时发回的状态可以自动处理,但是需要自己往请求中添加cookie时总是失败,折腾了很久,了解了HttpClient处理Cookie的细节,关于HttpClient中HTTP的状态管理,可以参考HttpClient的官方指南
2 示例
从bing获取搜索结果,代码如下:
deps.edn文件如下:
{
:deps {
org.clojure/clojure {:mvn/version "1.10.0"},
clj-http {:mvn/version "3.9.1"}, ; http
reaver {:mvn/version "0.1.2"} ; jsoup, html parser
}
}
实际代码:
(require '[clj-http.client :as client])
(require '[clj-http.cookies :as cookies])
(require '[reaver :as html]) (def ua "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20120101 Firefox/33.0")
(def cs (cookies/cookie-store)) (def http-header {:headers {"user-agent" ua
"accept-charset" "utf-8"}
:proxy-host "localhost" ;本地代理,用于测试
:proxy-port
:cookie-store cs
:insecure? true}) (defn search
"搜索关键字kw,返回[{:url :title :desc} ...]
kw 为搜索关键字
opt为附加选项:
:option http请求额外参数
:max-page 查询的最大页数,默认为3"
[kw & [opt]]
(let [base-url "https://www.bing.com"
option (get opt :option {})
max-page (get opt :max-page )]
(loop [page
url (str base-url "/search?q=" kw) ;这里没有用url编码,仅为演示用
result []]
(if (> page max-page)
result
(let [doc (-> (client/get url
(merge http-header option))
:body
html/parse)
entrys (html/extract-from doc "li.b_algo"
[:url :title :desc]
"h2 > a" (html/attr "href")
"h2 > a" html/text
"div > p" html/text)
r (apply conj result entrys)]
(if-let [next-path (-> (html/select doc "a.sb_pagn" )
(html/attr "href"))]
(recur (inc page)
(str base-url next-path)
r)
r)))))) (def googles (search "google" {:max-page }))
(count googles)
;; => 30
(first googles)
;; => {:url "http://www.google.cn/", :title "Google", :desc "2016-12-8 · google.com.hk 请收藏我们的网址"}
可以看到一页返回10个结果,如果要返回50(bing设置里最大结果数量),则要设置cookie项:
"SRCHHPGUSR" 的值为: "NRSLT=50"
下面添加cookie:
(cookies/clear-cookies cs) ;清除之前请求产生的cookies (def usr-cookie (cookies/to-basic-client-cookie
["SRCHHPGUSR" {
:discard false
:domain ".bing.com",
:path "/",
:value "NRSLT=50"
:expires (java.util.Date. )
}]))
(cookies/add-cookie cs usr-cookie) (cookies/get-cookies cs)
;; => {"SRCHHPGUSR" {:discard false, :domain ".bing.com", :expires #inst "10900-01-31T16:00:00.000-00:00", :path "/", :secure false, :value "NRSLT=50", :version 0}} (def googles (search "google" {:max-page }))
(count googles)
;; => 30
可以看到cookie并没有生效,在代理中也可以看到第一次请求时并没有带上添加的cookie。原因是HttpClient默认的Cookie specifications不会把.bing.com匹配到www.bing.com。
下面Api用法可以参考CookieOrigin API文档和cookie package文档:
(import org.apache.http.cookie.CookieOrigin)
(import (org.apache.http.impl.cookie DefaultCookieSpec
RFC6265LaxSpec
RFC6265StrictSpec
RFC2965Spec
RFC2109Spec
NetscapeDraftSpec
IgnoreSpec
BasicClientCookie2)) (def bing-co (CookieOrigin. "www.bing.com" "/" false)) (def match-spec #(.match %1 usr-cookie bing-co))
(def default-spec (DefaultCookieSpec.))
(match-spec default-spec)
;; => false
(def rfc6265-lax-spec (RFC6265LaxSpec.))
(match-spec rfc6265-lax-spec)
;; => false
(def rfc6265-strict-spec (RFC6265StrictSpec.))
(match-spec rfc6265-strict-spec)
;; => false
(def rfc2965-spec (RFC2965Spec.))
(match-spec rfc2965-spec)
;; => true
(def rfc2109-spec (RFC2109Spec.))
(match-spec rfc2109-spec)
;; => true
(def netscape-spec (NetscapeDraftSpec.))
(match-spec netscape-spec)
;; => true ;; 通过测试的几个spec,可以看到,默认只有rfc2*和netscape可以匹配.bing.com
;; 下面设置cookie的attr
(str usr-cookie)
;; => "[version: 0][name: SRCHHPGUSR][value: NRSLT=50][domain: .bing.com][path: /][expiry: Mon Feb 01 00:00:00 CST 10900]"
(.setAttribute usr-cookie BasicClientCookie2/DOMAIN_ATTR "true")
(str usr-cookie)
;; => "[version: 0][name: SRCHHPGUSR][value: NRSLT=50][domain: .bing.com][path: /][expiry: Mon Feb 01 00:00:00 CST 10900]"
;; 从表面上看不出设置了attr的区别,只有匹配时不同:
(.getAttribute usr-cookie "domain") ; DOMAIN_ATTR的值是"domain"
;; => "true" (def match-spec #(.match %1 usr-cookie bing-co))
(match-spec default-spec)
;; => true
(match-spec rfc6265-lax-spec)
;; => true
(match-spec rfc6265-strict-spec)
;; => true
(match-spec rfc2965-spec)
;; => true
(match-spec rfc2109-spec)
;; => true
(match-spec netscape-spec)
;; => true ;;再看搜索结果
(cookies/clear-cookies cs)
(cookies/add-cookie cs usr-cookie)
(def googles (search "google" {:max-page }))
(count googles)
;; => 78
;; 不是每页都有50条,不过重要的是通过.setAttribute,cookie起作用了
具体原因是rfc6265的规定,参考overflow的回答
经过上面的测试,也可以在clj-http中使用netscape的cookie-policy来达到目的,因为standard属于rfc6265-lax,默认也不会匹配:
(def usr-cookie (cookies/to-basic-client-cookie
["SRCHHPGUSR" {
:discard false
:domain ".bing.com",
:path "/",
:value "NRSLT=50"
:expires (java.util.Date. )
}])) (cookies/clear-cookies cs)
(cookies/add-cookie cs usr-cookie)
(def googles (search "google" {:max-page
:option {:cookie-policy :netscape}}))
(count googles)
;; => 78
但是这种方法是不推荐的,还是用.setAttribute比较好。
作者: ntestoc
Created: 2019-01-25 五 20:18
Apache HttpComponents中的cookie匹配策略的更多相关文章
- 在 Apache error_log 中看到多个信息,提示 RSA server certificate CommonName (CN) 与服务器名不匹配(转)
在 Apache error_log 中看到多个信息,提示 RSA server certificate CommonName (CN) 与服务器名不匹配. Article ID: 1500, cre ...
- JAVA中使用Apache HttpComponents Client的进行GET/POST请求使用案例
一.简述需求 平时我们需要在JAVA中进行GET.POST.PUT.DELETE等请求时,使用第三方jar包会比较简单.常用的工具包有: 1.https://github.com/kevinsawic ...
- Django 中的 cookie 和 session
一.cookie 由于HTTP协议是无状态的,而服务器端的业务必须是要有状态的.Cookie诞生的最初目的是为了存储web中的状态信息,以方便服务器端使用.比如判断用户是否是第一次访问网站.目前最新的 ...
- 4、Servlet中的Cookie 用于存储 web 页面的用户信息。
Servlet Cookie 处理 Cookie 是存储在客户端计算机上的文本文件,并保留了各种跟踪信息.Java Servlet 显然支持 HTTP Cookie. 识别返回用户包括三个步骤: 服务 ...
- WEB中的cookie
首先来一篇好文章,刚好看到的: 沉默中的狂怒 —— Cookie 大喷发---------------- http://www.cnblogs.com/index-html/p/mitm-cookie ...
- Apache HttpComponents Client 4.0快速入门/升级-2.POST方法访问网页
Apache HttpComponents Client 4.0已经发布多时,httpclient项目从commons子项目挪到了HttpComponents子项目下,httpclient3.1和 h ...
- 程序中的Cookie 和Session
这几天回家休息后,想想放假之前的几天,主要看的一些工作上的东西,发现对Session和Cookie这两个东西,我还是很陌生.恩,趁着有网,看了点相关的资料,打算整理下.一翻博客,发现已经有前辈已经对这 ...
- 在ASP.NET Core 中使用Cookie中间件
在ASP.NET Core 中使用Cookie中间件 ASP.NET Core 提供了Cookie中间件来序列化用户主题到一个加密的Cookie中并且在后来的请求中校验这个Cookie,再现用户并且分 ...
- Scrapy中使用cookie免于验证登录和模拟登录
Scrapy中使用cookie免于验证登录和模拟登录 引言 python爬虫我认为最困难的问题一个是ip代理,另外一个就是模拟登录了,更操蛋的就是模拟登录了之后还有验证码,真的是不让人省心,不过既然有 ...
随机推荐
- Hadoop shell 一查就会
Hadoop shell 命令有三种格式 hdfs + dfs (必须是dfs) Hadoop + dfs Hadoop + df 命令 说明 hadoop 版本查看 hadoop version h ...
- ajax请求下载Execl表
Execl表是经常要用到的存放二位数据的表格,Java也可以直接操作Execl表,经常用到的方式就是jxl和poi. 在这次项目中,我用到的poi往Execl中写数据,刚开始设计的是前端发送一个aja ...
- Netty面试
声明:此文章非本人所 原创,是别人分享所得,如有知道原作者是谁可以联系本人,如有转载请加上此段话 1.BIO.NIO 和 AIO 的区别? BIO:一个连接一个线程,客户端有连接请求时服务器端就需要 ...
- xamarin.android 实现 Activity 底部弹出对话框菜单
Resources/drawable 下新增如下文件: push_bottom_in.xml <?xml version="1.0" encoding="utf-8 ...
- 基于Udp的五子棋对战游戏
引言 本文主要讲述在局域网内,使用c#基于Udp协议编写一个对战的五子棋游戏.主要从Udp的使用.游戏的绘制.对战的逻辑这三个部分来讲解. 开发环境:vs2013,.Net4.0,在文章的末尾提供源代 ...
- BZOJ4144: [AMPPZ2014]Petrol(最短路 最小生成树)
题意 题目链接 Sol 做的时候忘记写题解了 可以参考这位大爷 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...
- 14:求10000以内n的阶乘
14:求10000以内n的阶乘 查看 提交 统计 提问 总时间限制: 5000ms 内存限制: 655360kB 描述 求10000以内n的阶乘. 输入 只有一行输入,整数n(0<=n< ...
- vue-router 实现导航守卫(路由卫士)
路由跳转前做一些验证,比如登录验证,是网站中的普遍需求. 对此,vue-route 提供的 beforeRouteUpdate 可以方便地实现导航守卫(navigation-guards). 导航守卫 ...
- linux 压缩解压命令zip、gz、tar.gz、bz2、tar.bz2、.tar.xz
linux压缩格式:.gz windows压缩格式:.zip .rar默认情况下,windows和linux都支持zip格式,都不需要安装额外软件. .zip格式 压缩zip /usr/bin/zip ...
- 深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)
相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...