最近做爬虫相关工作,我们平时用HttpWebRequest 比较多,每一个Url都要创建一个HttpWebRequest实例,

而且有些网站验证比较复杂,在登陆及后续抓取数据的时候,每次请求需要把上次的Cookie传递给这次请求。

记得这篇博客(http://www.cnblogs.com/dudu/archive/2013/03/05/httpclient.html)结尾,dudu总结了:

HttpClient最与众不同的地方是同一个HttpClient实例可以发出多次请求,每次请求是可以是完全不同的URL。

而一个HttpWebRequest实例对应于一个Url的一次请求。这才是HttpClient与HttpWebRequest的最大区别所在。

那么为什么不用HttpClient呢?

源码地址:https://github.com/zzhi/Spider4Net

本着学习的目的,那我就拿知乎练习一下,看看HttpClient好用否?

1,分析登陆页:https://www.zhihu.com/#signin

根据上图设置 DefaultRequestHeaders

 HttpClient h = new HttpClient(
new HttpClientHandler
{
//CookieContainer = cookies,
AutomaticDecompression = DecompressionMethods.GZip //防止返回的json乱码
| DecompressionMethods.Deflate
}); h.DefaultRequestHeaders.Add("UserAgent", Configs.ChromeAgent);
h.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4");
h.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, sdch");
h.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
//1.首页
var response = await h.GetAsync(index);
string content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
//获取隐藏的input值
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(content);
var xsdf = DocumentHelper.GetInputValue(doc, "_xsrf");//登录需要
nameValue["_xsrf"] = xsdf;
}
else
{
return null;
}

2,分析登陆页:https://www.zhihu.com/login/phone_num(我这里是手机和密码登录):

分析:除了要设置DefaultRequestHeaders,还需获取_xsrf的值<input type="hidden" name="_xsrf" value="3bc639713d3f8bb899009a7dfa37f9d2"/>,

这里还需注意:1, Content-Type: application/x-www-form-urlencoded; charset=UTF-8 该如何设置? 参考地址:http://ronaldrosiernet.azurewebsites.net/Blog/2013/12/07/posting_urlencoded_key_values_with_httpclient

2, 登录返回的JSON结果是乱码,该如何处理? 参考地址:http://stackoverflow.com/questions/9242472/retrieve-json-data-with-httpclient

//2.登陆
h.DefaultRequestHeaders.Clear();
h.DefaultRequestHeaders.Add("UserAgent", Configs.ChromeAgent);
h.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest");
h.DefaultRequestHeaders.Add("Origin", index);
h.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4");
h.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, sdch");
h.DefaultRequestHeaders.Add("Accept", "*/*");
//post参数
nameValue["password"] = PassWord;
nameValue["captcha_type"] = "cn";
nameValue["remember_me"] = "true";
nameValue["phone_num"] = Phone;
StringBuilder sb = new StringBuilder();
foreach (var key in nameValue.AllKeys)
{
sb.AppendFormat("{0}={1}&", key, nameValue[key]);
}
var str = sb.ToString().TrimEnd('&');
var request = new HttpRequestMessage(HttpMethod.Post, login);
var requestContent = str;
request.Content = new StringContent(requestContent, Encoding.UTF8, "application/x-www-form-urlencoded"); response = await h.SendAsync(request);
content = await response.Content.ReadAsStringAsync();
var dic = DocumentHelper.JsonToDic(content); if (dic.ContainsKey("msg"))
{
if (dic["msg"] != "登陆成功")//登录过于频繁,请稍等重试;errcode:100030
{
Console.WriteLine(dic["msg"]);
return null;
}
}

3. 登录成功后,后面就由大家随便折腾了。这里获取登陆后的首页信息吧。

//3.抓取首页
h.DefaultRequestHeaders.Clear();
h.DefaultRequestHeaders.Add("UserAgent", Configs.ChromeAgent);
h.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4");
h.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, sdch");
h.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
response = await h.GetAsync(index);
content = await response.Content.ReadAsStringAsync();

4,我也不对数据做处理了,看看结果:

上图是调试状态下的可视化工具视图。

源码地址:https://github.com/zzhi/Spider4Net, 里面也包含了用HttpWebRequest 方式登录的代码。

以上就是所有了,如果有时间给大家讲讲登录验证码的识别,但是这个略麻烦,需要根据具体网站的验证码训练一个验证码库,

复杂的无法识别的验证码就只能用打码兔了,其实也可以自己写个类似打码兔的软件,但需要有人值守,人工识别验证码。

这这么点东西,昨晚花费了3小时(9-12),今早写博客又花费了1小时。

HttpClient 模拟登陆知乎的更多相关文章

  1. Python 爬虫模拟登陆知乎

    在之前写过一篇使用python爬虫爬取电影天堂资源的博客,重点是如何解析页面和提高爬虫的效率.由于电影天堂上的资源获取权限是所有人都一样的,所以不需要进行登录验证操作,写完那篇文章后又花了些时间研究了 ...

  2. python模拟登陆知乎并爬取数据

    一些废话 看了一眼上一篇日志的时间 已然是5个月前的事情了 不禁感叹光阴荏苒其实就是我懒 几周前心血来潮想到用爬虫爬些东西 于是先后先重写了以前写过的求绩点代码 爬了草榴贴图,妹子图网,后来想爬婚恋网 ...

  3. 使用OKHttp模拟登陆知乎,兼谈OKHttp中Cookie的使用!

    本文主要是想和大家探讨技术,让大家学会Cookie的使用,切勿做违法之事! 很多Android初学者在刚开始学习的时候,或多或少都想自己搞个应用出来,把自己学的十八般武艺全都用在这个APP上,其实这个 ...

  4. Scrapy 模拟登陆知乎--抓取热点话题

    工具准备 在开始之前,请确保 scrpay 正确安装,手头有一款简洁而强大的浏览器, 若是你有使用 postman 那就更好了.           Python   1 scrapy genspid ...

  5. python模拟登陆知乎

    ---恢复内容开始--- 在完成前面的阶段的任务之后,我们现在已经能够尝试着去模拟登录一些网站了.在这里我们模拟登录一下知乎做一下实验.笔者在这里总共用了三天多的时间,下面给大家分享一下笔者是怎么一步 ...

  6. 第十二篇 requests模拟登陆知乎

    了解http常见状态码 可以通过输入错误的密码来找到登陆知乎的post:url 把Headers拉到底部,可以看到form data _xsrf是需要发送的,需要发送给服务端,否则会返回403错误,提 ...

  7. HTTPCLIENT 模拟登陆

    第一步构建忽略https验证的httpclient public static CloseableHttpClient getHttpClient() throws Exception { SSLCo ...

  8. python使用requests模块模拟登陆知乎

    from bs4 import BeautifulSoup import requests import time def captcha(captcha_data): with open(" ...

  9. httpClient模拟登陆校内某系统

    package com.huowolf; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpE ...

随机推荐

  1. Iterable,Iterator和forEach

    Iterable Interface Iterable<T> 方法: Iterator<T> iterator() Returns an iterator over a set ...

  2. 201621123037《Java程序设计》第二周学习总结

    #Week02-Java基本语法与类库 1. 本周学习总结 关键词:常量池.对象.null.不可变性.string对象拼接.字符串池 关键概念之间的联系:Java中有常量池,超出常量池以外的就会新开辟 ...

  3. Alpha阶段敏捷冲刺 ADY8

    一.举行站立式例会 今天也没有拍照片,人不齐. 二.团队报告 1.昨日已完成的工作 (1)创建一个test,并且将图片导入进去使其可以显示. 2.今日计划完成的工作 完成收尾工作.实现代码的连接. 3 ...

  4. PAT 甲级 1132 Cut Integer

    https://pintia.cn/problem-sets/994805342720868352/problems/994805347145859072 Cutting an integer mea ...

  5. 一个form表单,多个提交按钮

    技巧就是把提交的input的类型改成button!这样就可以实现多个按钮提交! 以下是案例: <form action="" id="tijiao"> ...

  6. linux自启动、定时启动脚本

    linux开机自启动 想让一个程序.脚本开机自启动,可以在/etc/rc.d目录下面找到rc.local文件,编辑该文件,在尾部加上需要运行的命令即可. 如: #cd /etc/rc.d #sudo ...

  7. SQL SERVER SA密码忘记,windows集成身份验证都登录不了不怎么办

    有时候SQL SERVER 的SA强密码策略真的很烦人,不同的系统密码策略又不一样,导致经常会忘记密码,这不,这回我本机的SQL SERVER很久不用了,彻底忘了密码是什么.查了一下资料还是找到了解决 ...

  8. Java多线程编程(学习笔记)

    一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过 ...

  9. 【C++】C++的构造函数

    构造函数是特殊的成员函数,只要创建类类型的对象,都要执行构造函数.构造函数的工作是保证每个对象的数据成员具有合适的初始值. class Sales_Item { public: //operation ...

  10. ZOJ2083_Win the Game

    这个题目很有趣,有博弈知识,又有一点智商题的感觉. 题意为给你一段长为n的的线段. 两个游戏者轮流在一段长为2,未被染色的线段上涂色. 无法涂色的游戏者输. 题目有点灵活.关键在于怎么得到Sg函数值呢 ...