java爬虫进阶 —— ip池使用,iframe嵌套,异步访问破解

Wesley13
• 阅读 615

写之前稍微说一下我对爬与反爬关系的理解

一、什么是爬虫
      爬虫英文是splider,也就是蜘蛛的意思,web网络爬虫系统的功能是下载网页数据,进行所需数据的采集。主体也就是根据开始的超链接,下载解析目标页面,这时有两件事,一是把相关超链接继续往容器内添加,二是解析页面目标数据,不断循环,直到没有url解析为止。举个栗子:我现在要爬取苏宁手机价格数据,爬取思路就是拿到第一页的url作为蜘蛛网的中心点开始,爬取当页的手机详情页面的价格信息以及下一页的url并添加进容器,这样循环往复只要存放url容器里有就会一直往下机械执行,直到尾页没有下一页,这就是个扩散的过程。

二、什么是反爬虫以及为什么要反
    反爬虫就是根据请求的一定的访问特征进行特殊处理,比如封Ip,弹验证码,返回不对应信息等等。

    至于反爬的原因大概有几点

    1、爬虫占总PV值高,就相当于一大群僵尸用户在访问你的网站,如果不管制,平白浪费服务器资源

    2、某些则是出于商业竞争问题必须反爬,不让自己的商业信息被对手批量获取。之前看到一个例子很贴切,两个to B公司对外售卖商品,而一家写了一个自动爬取对手网站商品价格并于己方商品价格对比,保持低于一定价格进行动态浮动的脚本,顾客在买之前肯定会对同行业价格进行了解,于是结果你们都懂,对方很快发现这边的公司动的手脚,于是一场哄哄烈烈爬与反爬的较量开始了

    3、还有就是一些无人认领的爬虫,可能用的人都忘了它的存在,一直在辛勤的爬

三 、常见的一些反爬手段
    1、根据ip访问频率以及数量上限封锁ip,那个用户会一秒访问页面几十次或者连续几小时每隔半秒访问一次,动作很明显,封就完事了。

2、还有就是加载页面时动态获取,而不是静态数据了。举个栗子,某东的价格信息是动态加载

    3、还有就是主体页面是异步加载嵌套在iframe里面的,并且 src="about:blank" ,这个正常下载下来的页面是没有内容的

    4、故意挖坑,在页面做一些隐藏链接,如果被访问明显是爬进去的爬虫,接下来就是一顿封

    5、后台对方问进行统计,对userAgent进行阈值判断,这个据说容易误伤

    6、还有就是在页面展示上进行做手脚,有的价格信息用图片展示,去哪儿网

    7、Cookie反扒,推荐链接,有一篇不错的介绍传送门

四、对前三种进行破解
    1.设立ip池循环进行循环访问

     首先我们从西刺等代理网站抓取一些免费的ip,其次进行无效ip过滤,这一步看情况吧,我个人实践是西刺网上得ip时而访问得通时而无效,所以我就去掉过滤得步骤,再就是用这些代理ip进行实际访问。

public class CsdnReadCount implements PageProcessor {

// IP地址代理库Map
private static Map<String, Integer> IPProxyRepository = new HashMap<>();
private static List keysArray = new ArrayList<>();
private static int index;

private Site site = Site
.me()
.setDomain("http://www.xicidaili.com/")
.setSleepTime(3000).setUserAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");

//按照顺序获取一个ip
public static HttpHost getRandomProxy() {

// 随机获取host:port,并构建代理对象
String host = keysArray.get(index);
if(index<keysArray.size()-1) {
index+=1;
}else {
index = 0;
}

int port = IPProxyRepository.get(host);
HttpHost proxy = new HttpHost(host, port); // 设置http代理
return proxy;
}

//抓取西刺网前两页上代理IP,因为不稳定,所以不做过滤
public void process(Page page) {

Html html = page.getHtml();
List hosts = html.xpath("//div[@id='body']/table/tbody/tr[@class='odd']/td[2]").replace("","").replace("","").all();
List ports = html.xpath("//div[@id='body']/table/tbody/tr[@class='odd']/td[3]").replace("","").replace("","").all();

keysArray.addAll(hosts);
for (int i=0;i<hosts.size();i++){
IPProxyRepository.put(hosts.get(i),Integer.valueOf(ports.get(i)));
}
}

public Site getSite() {
return site;
}

//请求页面,返回页面html代码
public static String getHttpContent(String url)throws IOException {

HttpHost proxy = getRandomProxy();
CloseableHttpClient httpClient = HttpClients.custom().setProxy(proxy).build(); // 创建httpclient对象

HttpGet request = new HttpGet(url); // 构建htttp get请求
request.setHeader("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0");

RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(1000)
.setSocketTimeout(5000).build();

request.setConfig(requestConfig);
String host = null;
Integer port = null;
if (proxy != null) {
host = proxy.getHostName();
port = proxy.getPort();
}

request.setHeader("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0");

try {

CloseableHttpResponse response = httpClient.execute(request);
String result = EntityUtils.toString(response.getEntity(), "utf-8");
System.out.println("ip"+host+"连接成功"+index);
System.out.println(result);
System.out.println(new Date());
}catch (Exception c){
System.out.println("ip"+host+"连接失败···");
System.out.println("index:"+index);
System.out.println(new Date());
}

return null;
}

public static void main(String[] args) throws InterruptedException,IOException{

CsdnReadCount csdnReadCount = new CsdnReadCount();
Spider spider = Spider.create(csdnReadCount);
spider.addUrl("http://www.xicidaili.com/nn/1");
spider.addUrl("http://www.xicidaili.com/nn/2");

spider.run();

getHttpContent("https://blog.csdn.net/caihaijiang/article/list/1");

}
}

    2.异步嵌套iframe的破解

    这里用到了selenium需要引入依赖

    准备: 下载谷歌驱动(谷歌驱动的版本一定要对应谷歌浏览器得版本,否则会报错)驱动下载传送门

                引入所需依赖  :  

org.seleniumhq.selenium selenium-java 3.3.1 package sample;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

import java.util.ArrayList;
import java.util.List;

public class SeleniumCloudMusic {

public static void main(String[] args) {

String key="webdriver.chrome.driver";
//谷歌驱动在你本地位置
String value="C:/Users/win 10/Desktop/暂存/chromedriver.exe";
System.setProperty(key,value);

WebDriver driver = new ChromeDriver();
driver.get("http://music.163.com/#");

WebElement iframe = driver.findElement(By.className("g-iframe"));
driver.switchTo().frame(iframe);

List elements = driver.findElements(By.xpath("//div[@class='u-cover u-cover-1']"));
List playLists = new ArrayList();

for (WebElement webElement:elements){
webElement.findElement(By.tagName("div"));
WebElement node = webElement.findElement(By.tagName("a"));
String url = node.getAttribute("href");

System.out.println(url);
playLists.add(url);

}

for (String str:playLists){

driver.get(str);
WebElement ifra = driver.findElement(By.className("g-iframe"));
driver.switchTo().frame(ifra);

WebElement subject = driver.findElement(By.tagName("h2"));

System.out.println(subject.getText());
}
}
}
3.动态加载破解

      此处依旧是某些网站加载数据通过ajax异步加载,你直接爬是没有信息的,所以需要爬取页面数据过程中单独生成请求获取价格数据

package sample;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import org.json.JSONArray;
import org.json.JSONObject;

public class JDPriceSplider implements PageProcessor {
private Site site = Site
.me()
.setDomain("https://item.jd.com")
.setSleepTime(3000);

public void process(Page page) {

String url = page.getUrl().get();
String id = url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf("."));
//拼接获取价格的url
String priceUrl = "https://p.3.cn/prices/mgets?pduid=1504781656858214892980&skuIds=J\_" + id;

//获取价格json信息
String priceJson = getHttpContent(priceUrl);
if (priceJson != null) {
// 解析json [{"op":"4899.00","m":"9999.00","id":"J_3133843","p":"4799.00"}] 将该json字符串封装成json对象
if (priceJson.contains("error")) { // 返回{"error":"pdos_captcha"},说明价格url已经不可用,更换pduid再做解析
} else {
JSONArray priceJsonArray = new JSONArray(priceJson);
JSONObject priceJsonObj = priceJsonArray.getJSONObject(0);
String priceStr = priceJsonObj.getString("p").trim();
Float price = Float.valueOf(priceStr);

System.out.println(price);
}
}
}

//相当于页面进行ajax调用,单独获取价格
public static String getHttpContent(String url) {

CloseableHttpClient httpClient = HttpClients.custom().build(); // 创建httpclient对象

HttpGet request = new HttpGet(url); // 构建htttp get请求
request.setHeader("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0");

RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(1000)
.setSocketTimeout(5000).build();
request.setConfig(requestConfig);

try {
CloseableHttpResponse response = httpClient.execute(request);

return EntityUtils.toString(response.getEntity());
} catch (Exception e) {
e.printStackTrace();
}

return null;
}

public Site getSite() {
return site;
}

public static void main(String[] args) {

//访问手机详情页面
Spider spider = Spider.create(new JDPriceSplider());
spider.addUrl("https://item.jd.com/6946605.html");
spider.run();
}
}
---------------------
作者:紫荆王朝
来源:CSDN
原文:https://blog.csdn.net/wu18296184782/article/details/80269274
版权声明:本文为博主原创文章,转载请附上博文链接!

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
把帆帆喂饱 把帆帆喂饱
2年前
爬虫
爬虫什么是爬虫使用编程语言所编写的一个用于爬取web或app数据的应用程序怎么爬取数据1.找到要爬取的目标网站、发起请求2.分析URL是如何变化的和提取有用的URL3.提取有用的数据爬虫数据能随便爬取吗?遵守robots.txt协议爬虫的分类通用网络爬虫百度,Google等搜索引擎,从一些初识的URL扩展到整个网站,主要为门户站点搜索引擎和大型网站服务采
Aimerl0 Aimerl0
2年前
Python网络爬虫与信息提取
title:Python网络爬虫与信息提取date:2020121001:00:23tags:Pythoncategories:学习笔记写在前面不知道写啥其实说实话TOC网络爬虫之规则安装requests库cmd命令行打开输入pip3installrequests,等待即可简单测试,爬一下bkjwpythonimportrequ
Wesley13 Wesley13
2年前
Java爬虫之JSoup使用教程
title:Java爬虫之JSoup使用教程date:201812248:00:000800update:201812248:00:000800author:mecover:https://imgblog.csdnimg.cn/20181224144920712(https://www.oschin
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这