并不是所有的网站都能够敞开心扉让你看个透彻,它们总要给你出些难题让你觉得有些东西是来之不易的,往往,这也更加激发你的激情和斗志!
从里就有网友提出可以通过获取 cookie 的方式来登录,不需要借助 selenium 这样的模拟浏览器操作了,到后来在公众号里一号友说豆瓣如何实现登录,以及近期园友都有提到想获取更多的网站数据是需要登录的…… 登录,一直是爬虫界躲不了也绕不开的话题。
之前已经试过通过启动浏览器,模拟人工操作填写用户名和密码并点击登录来完成登录。 这次准备由台前模式切换到幕后,研究下不用启动浏览器如何实现使用后台代码就模拟登录豆瓣电影君。
类似这样的登录界面(movie.douban.com),我们只要填写用户名和密码,乐意的话选中 "下次自动登录",然后点击登录按钮,不出意外(如果你总是调戏人家,屡次输入错误,人家不会用小锤锤捶你胸,但是搞个验证码也够你喝一壶的了),你就登录成功了。
看着还是比较简单,但是在浏览器后面,实际上已经做了不少事儿~~~
如果是 Chrome 浏览器,可以按 F12,切到 Network 选项,在点击页面中的登录后,你可以看到唰唰唰的请求,好比这样
其中最关键的发生在第一条,即通过发送 HTTP Post 请求与服务器交互,请求登录,在这条请求中你可以看到很熟悉的内容
没错,你在登录网站的时候,实际上是与服务器做了一次通讯,验证成功后,服务器才让你登录网站。
如果网站像上面这样的情况,其实很好登录,比如在 postman 中填写这些对应的参数就能够成功登录,但是有情操的网站都会有验证码,一般会出现在多次登录失败或者登录网站过于频繁就会出现验证码,好比这样
则对应的 post 请求如下
这时候我们使用 postman 实施登录,结果似乎不尽如人意,之所以产生这样的效果时因为这个 captcha-id 在每次请求的时候都会重新生成,感觉是和验证码绑定的,所以即使你在请求参数中带上了 captcha-id 也无济于事,因为这次的 cookie 已经不能使用上次的 cookie,直白说就是这次我们又有了一个新的验证码,但是使用的 captcha-solution 却是上一次的(一张旧船票如何登上进入的新船)。
旧船票登不上船是因为日期不对,就是这里的 captcha-solution 和 captcha-id 不匹配,所以需要
- package com.jackie.crawler.doubanmovie.utils;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import org.apache.http.HttpEntity;
- import org.apache.http.HttpResponse;
- import org.apache.http.NameValuePair;
- import org.apache.http.client.ClientProtocolException;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.entity.UrlEncodedFormEntity;
- import org.apache.http.client.methods.HttpGet;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.impl.client.DefaultHttpClient;
- import org.apache.http.message.BasicNameValuePair;
- import org.apache.http.util.EntityUtils;
- import org.json.JSONException;
- import org.json.JSONObject;
- /**
- * Created by Jackie on 2017/3/12.
- */
- public class LoginTest {
- private static HttpClient httpClient=new DefaultHttpClient();
- //主登录入口
- public static void loginDouban(){
- String redir="https://www.douban.com/people/your_home_page/"; // 输入你登录成功后要跳转的网页
- String login_src="https://accounts.douban.com/login";
- String form_email="your_username"; // 你的用户名
- String form_password="your_password"; // 你的密码
- String captcha_id=getImgID();
- String login="登录";
- String captcha_solution="";
- System.out.println("请输入验证码:");
- BufferedReader buff=new BufferedReader(new InputStreamReader(System.in));
- try {
- captcha_solution=buff.readLine();
- } catch (IOException e) {
- e.printStackTrace();
- }
- //构建参数
- List list=new ArrayList();
- list.add(new BasicNameValuePair("redir", redir));
- list.add(new BasicNameValuePair("form_email", form_email));
- list.add(new BasicNameValuePair("form_password", form_password));
- list.add(new BasicNameValuePair("captcha-solution", captcha_solution));
- list.add(new BasicNameValuePair("captcha-id", captcha_id));
- list.add(new BasicNameValuePair("login", login));
- HttpPost httpPost = new HttpPost(login_src);
- try {
- httpPost.setEntity(new UrlEncodedFormEntity(list));
- HttpResponse response=httpClient.execute(httpPost);
- HttpEntity entity=response.getEntity();
- String result=EntityUtils.toString(entity,"utf-8");
- HttpGet httpGet=new HttpGet(redir);
- HttpResponse response1=httpClient.execute(httpGet);
- HttpEntity entity1=response1.getEntity();
- String result1=EntityUtils.toString(entity1,"utf-8");
- System.out.println(result1);
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /**
- * 获取验证码图片"token"值
- * @return token
- */
- private static String getImgID(){
- String src="https://www.douban.com/j/misc/captcha";
- HttpGet httpGet=new HttpGet(src);
- String token="";
- try {
- HttpResponse response=httpClient.execute(httpGet);
- HttpEntity entity=response.getEntity();
- String content=EntityUtils.toString(entity,"utf-8");
- Map mapList=getResultList(content);
- token=mapList.get("token");
- String url="https:"+mapList.get("url");
- downImg(url);
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return token;
- }
- /**
- * 用JSON 把数据格式化,并生成迭代器,放入Map中返回
- * @param content 请求验证码时服务器返回的数据
- * @return Map集合
- */
- public static Map getResultList(String content){
- Map maplist=new HashMap();
- try {
- JSONObject jo=new JSONObject(content);
- Iterator it = jo.keys();
- String key="";
- String value="";
- while(it.hasNext()){
- key=(String) it.next();
- if ("r".equals(key)) {
- value = jo.getBoolean(key) + "";
- }else {
- value=jo.getString(key);
- }
- maplist.put(key, value);
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
- return maplist;
- }
- /**
- * 此方法是下载验证码图片到本地
- * @param src 给个验证图片完整的地址
- */
- private static void downImg(String src){
- File fileDir=new File("D://爬虫测试/jackie");
- if(!fileDir.exists()){
- fileDir.mkdirs();
- }
- File file=new File("D://爬虫测试/jackie/jackie.png");
- if(file.exists()){
- file.delete();
- }
- InputStream input = null;
- FileOutputStream out= null;
- HttpGet httpGet=new HttpGet(src);
- try {
- HttpResponse response=httpClient.execute(httpGet);
- HttpEntity entity = response.getEntity();
- input = entity.getContent();
- int i=-1;
- byte[] byt=new byte[1024];
- out=new FileOutputStream(file);
- while((i=input.read(byt))!=-1){
- out.write(byt);
- }
- System.out.println("图片下载成功!");
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- loginDouban();
- }
- }
以上代码参考自网友。
执行的结果如下:
由此可见,已经通过模拟登录的方式成功登录网站。
上面的操作还是不够自动化, 主要是验证码这个环节, 需要人工输入下载到本地图片的验证码内容。本来想通过 Tesseract-OCR 技术来自动识别验证码,但是在分析验证码需要针对性的用到二值化、中值过滤等都遇到了困难,最终还是没能通过这种方式,实现全自动化模拟登录。
但是可以大概介绍下在这方面做的尝试:
这样的命令将
- tesseract 1.jpg result
输入通过 tesseract 处理将识别的讲过存入名为 result 的 txt 文件中。
- 1.jpg
代码已更新到
如果您觉得阅读本文对您有帮助,请点一下 "推荐" 按钮,您的 "推荐" 将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注 JackieZheng 的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。(有些闲言碎语我可能会写在公众号)
来源: http://www.cnblogs.com/bigdataZJ/p/doubanmovie5.html