JAVA爬虫初识之模拟登录

在设计一个爬虫的时候,在第一步对网站的大概浏览了解情况是会发现有些网站在访问之前是需要登录的,否则是无法访问到有我们需要的数据的子页面的,这个时候就要在之前的基础上增加一个模拟登录的步骤。
其实模拟登录的步骤跟之前所说的httpclient基本是一样的,只不过现在网站登录基本用的是post方法,同时在里面携带登录所需要的参数如账号密码,所以我们只需要模拟实际操作,将待爬取网站所需要的参数对应的设置到httppost中,下面以模拟知乎登录为例:

1. 确定登录所需要携带的参数:

首先确定登录所需要携带的参数,这里仍用到之前提过的抓包工具fiddler,通过对登录数据的抓取,最后发现需要携带以下参数:
这里写图片描述
之后分析一下这些参数:
- _xsrf:起初我也对这个参数很疑惑具体是哪来的,但经过对登录页面网页源代码的查找发现这是在每次发起www.zhihu.com请求时在网页源代码中携带返回的一个参数且每次都是不一样的如图
这里写图片描述
- captcha:显而易见,验证码。
- captcha_type:验证码的类型。
- email:账号。
- password:密码。

2.获取参数:
  • _xsrf:对https://www.zhihu.com发起请求,下载登录页面,再直接从页面取值即可。取值代码
/**
     * 获取_xsrf
     * getPageHtml()是下载页面方法
     */
    public String get_xsrf("https://www.zhihu.com") {
        String page = getPageHtml("https://www.zhihu.com");
        Document doc = Jsoup.parse(page);
        Elements srfs = doc.getElementsByAttributeValue("name", "_xsrf");
        String xsrf = srfs.first().attr("value");
        return xsrf;
    }
  • captcha:验证码。起初登录时发现知乎登录用的是中文验证码,需要找出倒写的汉字,发送到服务器的参数是鼠标点击的位置,服务器会根据位置是否与图片倒写汉字位置匹配来判断正确与否。嫌参数分析麻烦(其实是太菜。。)多次实验发现知乎还有输入数字字母的验证码,这个就简单多了而且这种验证码少携带一个captcha_type参数:
    这里写图片描述
    这里写图片描述所以只需要将验证码图片下载到本地在对应的设置参数就行了。首先是下载验证码图片,通过对页面源代码的分析并没有找到图片,那就应该是通过js传过来的,抓包分析果然找到了加载验证码的步骤:
    这里写图片描述知道了来源,那就简单了只需要像_xsrf一样请求相应的地址就行了,然而观察地址又难住了,这个r参数是哪儿来的。。经过多次抓包发这个r每次都不一样而且毫无规律可循,于是猜测这可能是个随机数,通过浏浏览器将这个r改成随机数请求果然得到了一张验证码图片:
    这里写图片描述接下来就是按部就班的下载了;得到了图片第二步就是设置验证码参数。由于技术有限无法做到智能识别输入,所以选择从控制台输入的方式设置验证码参数。。即在首次登录是下载验证码到本地之后人工查看验证码之后控制台输入验证码设置到请求参数中。下载输入代码如下:
/**
     * 下载验证码到本地
     * @param url
     * @param desFileName
     * @return
     * @throws MalformedURLException 
     */
    public boolean downloaderCapter(String url,String desFileName) throws MalformedURLException {
        boolean flag = false;
        String page = getPageHtml(url);
        Document doc = Jsoup.parse(page);
        Elements capchas = doc.select("img.Captcha-image");
        System.out.println(capchas.size());
        if (capchas.size()==0) {
            System.out.println("不需要验证码");
        }else {
            String caurl = "";
            //生成随机数
            Random rnd = new Random();
            StringBuilder sb = new StringBuilder();  
            for(int i=0; i < 13; i++) {
                sb.append((char)('0' + rnd.nextInt(10)));  
            }
            String id = sb.toString();
            System.out.println(id);

                caurl = "https://www.zhihu.com/captcha.gif?r="+id+"&type=login";
            //下载验证码图片
            URL captcha_url = new URL(caurl);
            System.out.println(captcha_url);
            File file = new File(desFileName);
            if (file.exists()) {
                file.delete();
            }
            try {
                URLConnection con = captcha_url.openConnection();  
                InputStream is = con.getInputStream();  
                // 1K的数据缓冲  
                byte[] bs = new byte[1024];  
                // 读取到的数据长度  
                int len;  
                OutputStream os = new FileOutputStream(file);  
                // 开始读取  
                while ((len = is.read(bs)) != -1) {  
                    os.write(bs, 0, len);  
                }
                is.close();
                os.close();
                flag = true;
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }  
        }
        return flag;
    }
  • 账号与密码:相对应的账号密码明文即可。

    相对来说,知乎是一个登录比较简单的网站,登录中只是加了一个可以在网页中寻找到的字符串和验证码,对于一些要求比较高的网站,还会对密码进行加密,以密文的形式作为参数发送至服务器,这时候就要了解加密方法对自己的参数进行加密发送。总的来说就是服务器需要什么参数你就相应的给它什么参数。

3.登录实现:

在获取所有参数之后就简单了只要按照httpclient模拟请求就可以了(原以为),代码如下:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.net.ssl.SSLContext;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;



public class ZhiHu3 {
    private String mainurl = "https://www.zhihu.com";
    private String email = "";
    private String password = "";
    private String _xsrf = "";
    boolean daili = false;
    HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
    //CloseableHttpClient httpClient = httpClientBuilder.build();
    CloseableHttpClient httpClient = createSSLClientDefault();
    private HttpHost proxy = new HttpHost("127.0.0.1",8888,"http");
    private RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
    private String useage = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36";
    private RequestConfig configtime=RequestConfig.custom().setCircularRedirectsAllowed(true).setSocketTimeout(10000).setConnectTimeout(10000).build();

    public ZhiHu3() {

    }


    public ZhiHu3(String email, String password) {

        this.email = email;
        this.password = password;
    }
    // client工具函数,信任对方(https)所有证书
    private CloseableHttpClient createSSLClientDefault(){  
        try {  
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {  
                //信任所有证书  
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
                    return true;  
                }  
            }).build();  
            SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext);  
            return HttpClients.custom().setSSLSocketFactory(sslFactory).build();  
        } catch (Exception e) {  
        }  
        return  HttpClients.createDefault();  
    }

    public String getPageHtml(String url) {
        String html="";
        HttpGet httpget = new HttpGet(url);
        httpget.addHeader("User-Agent", useage);
        httpget.setConfig(configtime);
        try {
            CloseableHttpResponse response = httpClient.execute(httpget);
            HttpEntity entity = response.getEntity();
            html = EntityUtils.toString(entity, "utf-8");
            httpget.releaseConnection();
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return html;
    }
    /**
     * 下载验证码到本地
     * @param url
     * @param desFileName
     * @return
     * @throws MalformedURLException 
     */
    public boolean downloaderCapter(String url,String desFileName) throws MalformedURLException {
        boolean flag = false;
        String page = getPageHtml(url);
        Document doc = Jsoup.parse(page);
        Elements capchas = doc.select("img.Captcha-image");
        System.out.println(capchas.size());
        if (capchas.size()==0) {
            System.out.println("不需要验证码");
        }else {
            String caurl = "";
            //生成随机数
            Random rnd = new Random();
            StringBuilder sb = new StringBuilder();  
            for(int i=0; i < 13; i++) {
                sb.append((char)('0' + rnd.nextInt(10)));  
            }
            String id = sb.toString();
            caurl = "https://www.zhihu.com/captcha.gif?r="+id+"&type=login";
            //下载验证码图片
            File file = new File(desFileName);
            if (file.exists()) {
                file.delete();
            }
            try {
                HttpGet getCaptcha = new HttpGet(caurl);
                CloseableHttpResponse imageResponse = httpClient.execute(getCaptcha);
                byte[] bs = new byte[1024];  
                int len;
                OutputStream os = new FileOutputStream(file);  
                while ((len = imageResponse.getEntity().getContent().read(bs)) != -1) {
                    os.write(bs,0,len);
                    flag = true;
                }
                os.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }  
        }
        return flag;
    }
    /**
     * 获取_xsrf
     */
    public String get_xsrf(String url) {
        String page = getPageHtml(url);
        Document doc = Jsoup.parse(page);
        Elements srfs = doc.getElementsByAttributeValue("name", "_xsrf");
        String xsrf = srfs.first().attr("value");
        return xsrf;
    }


    public void login() throws IOException {
        List<NameValuePair> para = new ArrayList<NameValuePair>();
        _xsrf=get_xsrf(mainurl);
        System.out.println(_xsrf);
        para.add(new BasicNameValuePair("_xsrf", _xsrf));
        Map<String, String> header = new HashMap<String, String>();
        header.put("Content-Type", "application/x-www-form-urlencoded");
        header.put("Referer","https://www.zhihu.com/");
        header.put("User-Agent", useage);
        header.put("X-Requested-With", "XMLHttpRequest");
        header.put("Host", "www.zhihu.com");
        header.put("Origin", "https://www.zhihu.com");
        boolean flag = downloaderCapter(mainurl, "D:\\image.png");
        if (flag) {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("请输入验证码:");
            String captcha = br.readLine();
            para.add(new BasicNameValuePair("captcha",captcha));
        }
        para.add(new BasicNameValuePair("email", email));
        para.add(new BasicNameValuePair("password", password));
        para.add(new BasicNameValuePair("rememberme", "true"));
        HttpPost httppost = new HttpPost("https://www.zhihu.com/login/email");
        for (String string : header.keySet()) {
            httppost.addHeader(string, header.get(string));
        }
        httppost.addHeader("X-Xsrftoken", _xsrf);
        if (daili) {
            httppost.setConfig(config);
        }
        httppost.setEntity(new UrlEncodedFormEntity(para,"utf-8"));
        CloseableHttpResponse res = httpClient.execute(httppost);
        int statuts_code = res.getStatusLine().getStatusCode();
        System.out.println(statuts_code);
        System.out.println(EntityUtils.toString(res.getEntity(),"utf-8"));
        httppost.releaseConnection();
    }




    public static void main(String[] args) {

        ZhiHu3 zhihu = new ZhiHu3("xxxxxxxxx@qq.com","xxxxxxxx");
        try {
            zhihu.login();
            String html = zhihu.getPageHtml("https://www.zhihu.com/question/following");
            //System.out.println(html);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

原来创建httpclient用的是httpClientBuilder.build()方法,但是在实践中发现偶尔会报关于SSL证书问题的错误,所以加了一个工具函数。登录成功后就可抓取自己想要的数据了,我这里是在登录成功后访问我的关注页面。输出返回码为200,表示登录成功。
这里写图片描述

  • 12
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的工作流程包括以下几个关键步骤: URL收集: 爬虫从一个或多个初始URL开始,递归或迭代地发现新的URL,构建一个URL队列。这些URL可以通过链接分析、站点地图、搜索引擎等方式获取。 请求网页: 爬虫使用HTTP或其他协议向目标URL发起请求,获取网页的HTML内容。这通常通过HTTP请求库实现,如Python中的Requests库。 解析内容: 爬虫对获取的HTML进行解析,提取有用的信息。常用的解析工具有正则表达式、XPath、Beautiful Soup等。这些工具帮助爬虫定位和提取目标数据,如文本、图片、链接等。 数据存储: 爬虫将提取的数据存储到数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。 遵守规则: 为避免对网站造成过大负担或触发反爬虫机制,爬虫需要遵守网站的robots.txt协议,限制访问频率和深度,并模拟人类访问行为,如设置User-Agent。 反爬虫应对: 由于爬虫的存在,一些网站采取了反爬虫措施,如验证码、IP封锁等。爬虫工程师需要设计相应的策略来应对这些挑战。 爬虫在各个领域都有广泛的应用,包括搜索引擎索引、数据挖掘、价格监测、新闻聚合等。然而,使用爬虫需要遵守法律和伦理规范,尊重网站的使用政策,并确保对被访问网站的服务器负责。
要使用Java实现支付宝的模拟登录,可以使用HttpClient类库进行请求的发送和接收。下面是一个简单的示例代码,可以帮助你了解如何实现: ```java import java.io.IOException; import java.net.URI; import java.util.ArrayList; 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.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; public class AlipayLogin { public static void main(String[] args) throws IOException { // 创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建HttpPost对象 HttpPost httpPost = new HttpPost("https://auth.alipay.com/login/index.htm"); // 设置请求头 httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"); // 构建请求参数 List<NameValuePair> paramList = new ArrayList<>(); paramList.add(new BasicNameValuePair("username", "your username")); paramList.add(new BasicNameValuePair("password", "your password")); paramList.add(new BasicNameValuePair("goto", "https://my.alipay.com/portal/i.htm")); paramList.add(new BasicNameValuePair("service", "https://my.alipay.com/portal/i.htm")); paramList.add(new BasicNameValuePair("sign_type", "RSA")); paramList.add(new BasicNameValuePair("rnd", "random number")); paramList.add(new BasicNameValuePair("logonId", "")); paramList.add(new BasicNameValuePair("logonType", "")); paramList.add(new BasicNameValuePair("jua", "")); paramList.add(new BasicNameValuePair("mobileLoginLink", "")); paramList.add(new BasicNameValuePair("cssStyle", "")); paramList.add(new BasicNameValuePair("fp", "")); paramList.add(new BasicNameValuePair("needCheck", "")); paramList.add(new BasicNameValuePair("pwdType", "")); paramList.add(new BasicNameValuePair("QRCodeLoginLink", "")); paramList.add(new BasicNameValuePair("gotoUrl", "")); paramList.add(new BasicNameValuePair("app_name", "taobao")); paramList.add(new BasicNameValuePair("fromSite", "0")); paramList.add(new BasicNameValuePair("form", "alipayLogin")); paramList.add(new BasicNameValuePair("pubKey", "")); paramList.add(new BasicNameValuePair("loginScene", "taobao_login")); // 创建UrlEncodedFormEntity对象 UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(paramList, "UTF-8"); httpPost.setEntity(formEntity); // 发送Post请求 HttpResponse response = httpClient.execute(httpPost); // 获取响应实体 HttpEntity entity = response.getEntity(); // 将响应实体转换为字符串输出 String result = EntityUtils.toString(entity, "UTF-8"); System.out.println(result); // 关闭HttpClient对象 httpClient.close(); } } ``` 在这个示例中,我们通过构建HttpPost请求实现了模拟登录,使用了HttpClient类库发送请求并获取响应实体。需要注意的是,请求参数中的用户名和密码应该替换为你自己的支付宝账号和密码,同时还需要将请求头中的User-Agent替换为你自己的浏览器User-Agent。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值