
java爬虫抓取动态网页
java爬虫抓取动态网页(一家出数据库表结构下面贴出爬虫的动态代理实现爬虫)
网站优化 • 优采云 发表了文章 • 0 个评论 • 61 次浏览 • 2022-02-09 19:23
作者的公司是一个区块链门户网站,网站的很多信息、新闻、视频等数据都是通过爬取第三方网站获取的,需要获取从很多网站来爬取数据,如果每个数据源网站都需要编写单独的接口来爬取,工作量无疑是巨大的,因为作者想到了通过动态实现一套爬虫机制proxy,每次爬取一个新的数据源,只需要在数据库中添加一个数据源,不需要修改代码。
废话不多说,下面贴出数据库表结构
DROP TABLE IF EXISTS `yiyi_crawler_website`;
CREATE TABLE `yiyi_crawler_website` (
`id` bigint(16) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`url` varchar(255) DEFAULT NULL COMMENT '网站链接(抓取内容的接口)',
`interval` bigint(16) DEFAULT '0' COMMENT '抓取时间间隔(以毫秒为单位)',
`website_type` tinyint(20) DEFAULT NULL COMMENT '网站类型(1、快讯)',
`website_name` varchar(32) DEFAULT NULL COMMENT '网站名',
`source_link` varchar(255) DEFAULT NULL COMMENT '来源链接',
`data_field` varchar(32) DEFAULT NULL COMMENT '数据所在字段,如果没有,为空则直接取数(多级以.连接,如果:data.items表示data下面的items为内容列表)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `yiyi_crawler_website_content`;
CREATE TABLE `yiyi_crawler_website_content` (
`id` bigint(16) NOT NULL AUTO_INCREMENT,
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`website_id` bigint(16) DEFAULT NULL COMMENT '网站ID',
`content_name` varchar(16) DEFAULT NULL COMMENT '内容名',
`table_name` varchar(32) DEFAULT NULL COMMENT '所属表名',
`column_name` varchar(32) DEFAULT NULL COMMENT '所属字段名',
`return_field` varchar(32) DEFAULT NULL COMMENT '当前要抓取的字段所返回的字段',
`field_type` tinyint(2) DEFAULT '2' COMMENT '字段类型(1、日期2、数值0、其他)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
下面贴出爬虫的动态代理实现,基于cglib框架。
/**
* 爬虫任务代理接口
*
* @author liyi
* @create 2018-03-17 16:58
**/
public interface CrawlerProxy {
/**
* 任务开始
* @param website
*/
void start(CrawlerWebsiteModelOut website);
}
/**
* 爬虫任务类
*
* @author liyi
* @create 2018-03-17 18:21
**/
public class CrawlerTask implements CrawlerProxy {
@Override
public void start(CrawlerWebsiteModelOut website) {
System.out.println("爬虫任务开始");
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import java.util.*;
/**
* 爬虫定时任务
*
* @author liyi
* @create 2018-03-17 18:35
**/
public class CrawlerTimerTask extends TimerTask {
private CrawlerWebsiteModelOut website = null;
@Override
public void run() {
String json = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
String strs[] = website.getDataField().split(".");
List dataList = new ArrayList();
Arrays.stream(strs).forEach(s -> {
dataList.clear();
String data = JSON.parseObject(json, new TypeReference() {}.getType());
dataList.add(data);
});
}
public void setWebsite(CrawlerWebsiteModelOut website) {
this.website = website;
}
public CrawlerWebsiteModelOut getWebsite() {
return website;
}
}
import com.alibaba.fastjson.JSONObject;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import com.lynn.yiyi.service.CrawlerService;
import com.lynn.yiyi.utils.SpringUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 爬虫动态代理类
*
* @author liyi
* @create 2018-03-17 18:22
**/
public class CrawlerCglibProxy implements MethodInterceptor {
private Map timerMap = new HashMap();
private Enhancer enhancer = new Enhancer();
Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object o = proxy.invokeSuper(obj,args);
if("start".equals(method.getName())){
if(args[0] instanceof CrawlerWebsiteModelOut){
CrawlerWebsiteModelOut website = (CrawlerWebsiteModelOut)args[0];
if(timerMap.get(website.getId()) == null){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
String data = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
String strs[] = website.getDataField().split("\\.");
for (String s : strs) {
JSONObject object = JSONObject.parseObject(data);
data = object.getString(s);
}
//TODO 这里将爬取到的数据写到数据库对应的表中
}
}, 0, website.getInterval());
timerMap.put(website.getId(),timer);
}
}
}
return o;
}
public static T create(Class cls){
CrawlerCglibProxy proxy = new CrawlerCglibProxy();
return (T)proxy.getProxy(cls);
}
}
import java.util.ArrayList;
import java.util.List;
/**
* 网站爬虫输出参数
*
* @author liyi
* @create 2018-03-17 17:04
**/
public class CrawlerWebsiteModelOut extends BaseModelOut {
private String url;
private Long interval;
private Integer websiteType;
private String websiteName;
private String sourceLink;
private String dataField;
private List contentList = new ArrayList();
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Long getInterval() {
return interval;
}
public void setInterval(Long interval) {
this.interval = interval;
}
public Integer getWebsiteType() {
return websiteType;
}
public void setWebsiteType(Integer websiteType) {
this.websiteType = websiteType;
}
public String getWebsiteName() {
return websiteName;
}
public void setWebsiteName(String websiteName) {
this.websiteName = websiteName;
}
public String getSourceLink() {
return sourceLink;
}
public void setSourceLink(String sourceLink) {
this.sourceLink = sourceLink;
}
public String getDataField() {
return dataField;
}
public void setDataField(String dataField) {
this.dataField = dataField;
}
public List getContentList() {
return contentList;
}
public void setContentList(List contentList) {
this.contentList = contentList;
}
}
/**
* 爬虫网站内容输出参数
*/
public class CrawlerWebsiteContentModelOut extends BaseModelOut{
private Long websiteId;
private String contentName;
private String tableName;
private String columnName;
private String returnField;
private Integer fieldType;
public Long getWebsiteId() {
return websiteId;
}
public void setWebsiteId(Long websiteId) {
this.websiteId = websiteId;
}
public String getContentName() {
return contentName;
}
public void setContentName(String contentName) {
this.contentName = contentName;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getReturnField() {
return returnField;
}
public void setReturnField(String returnField) {
this.returnField = returnField;
}
public Integer getFieldType() {
return fieldType;
}
public void setFieldType(Integer fieldType) {
this.fieldType = fieldType;
}
}
import java.util.Date;
/**
* 基础输出参数
*
* @author liyi
* @create 2018-03-17 17:02
**/
public abstract class BaseModelOut{
private Long id;
private Date create;
private Date modified;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getCreate() {
return create;
}
public void setCreate(Date create) {
this.create = create;
}
public Date getModified() {
return modified;
}
public void setModified(Date modified) {
this.modified = modified;
}
}
下面给出测试的主要方法
public static void main(String[] args) {
CrawlerProxy proxy = CrawlerFactory.create();
proxy.start(website);//website即当前要爬取的网站对象,可以从数据库中读取
}
调用main方法启动定时器,定时从指定网站爬取数据。 查看全部
java爬虫抓取动态网页(一家出数据库表结构下面贴出爬虫的动态代理实现爬虫)
作者的公司是一个区块链门户网站,网站的很多信息、新闻、视频等数据都是通过爬取第三方网站获取的,需要获取从很多网站来爬取数据,如果每个数据源网站都需要编写单独的接口来爬取,工作量无疑是巨大的,因为作者想到了通过动态实现一套爬虫机制proxy,每次爬取一个新的数据源,只需要在数据库中添加一个数据源,不需要修改代码。
废话不多说,下面贴出数据库表结构
DROP TABLE IF EXISTS `yiyi_crawler_website`;
CREATE TABLE `yiyi_crawler_website` (
`id` bigint(16) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`url` varchar(255) DEFAULT NULL COMMENT '网站链接(抓取内容的接口)',
`interval` bigint(16) DEFAULT '0' COMMENT '抓取时间间隔(以毫秒为单位)',
`website_type` tinyint(20) DEFAULT NULL COMMENT '网站类型(1、快讯)',
`website_name` varchar(32) DEFAULT NULL COMMENT '网站名',
`source_link` varchar(255) DEFAULT NULL COMMENT '来源链接',
`data_field` varchar(32) DEFAULT NULL COMMENT '数据所在字段,如果没有,为空则直接取数(多级以.连接,如果:data.items表示data下面的items为内容列表)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `yiyi_crawler_website_content`;
CREATE TABLE `yiyi_crawler_website_content` (
`id` bigint(16) NOT NULL AUTO_INCREMENT,
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`website_id` bigint(16) DEFAULT NULL COMMENT '网站ID',
`content_name` varchar(16) DEFAULT NULL COMMENT '内容名',
`table_name` varchar(32) DEFAULT NULL COMMENT '所属表名',
`column_name` varchar(32) DEFAULT NULL COMMENT '所属字段名',
`return_field` varchar(32) DEFAULT NULL COMMENT '当前要抓取的字段所返回的字段',
`field_type` tinyint(2) DEFAULT '2' COMMENT '字段类型(1、日期2、数值0、其他)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
下面贴出爬虫的动态代理实现,基于cglib框架。
/**
* 爬虫任务代理接口
*
* @author liyi
* @create 2018-03-17 16:58
**/
public interface CrawlerProxy {
/**
* 任务开始
* @param website
*/
void start(CrawlerWebsiteModelOut website);
}
/**
* 爬虫任务类
*
* @author liyi
* @create 2018-03-17 18:21
**/
public class CrawlerTask implements CrawlerProxy {
@Override
public void start(CrawlerWebsiteModelOut website) {
System.out.println("爬虫任务开始");
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import java.util.*;
/**
* 爬虫定时任务
*
* @author liyi
* @create 2018-03-17 18:35
**/
public class CrawlerTimerTask extends TimerTask {
private CrawlerWebsiteModelOut website = null;
@Override
public void run() {
String json = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
String strs[] = website.getDataField().split(".");
List dataList = new ArrayList();
Arrays.stream(strs).forEach(s -> {
dataList.clear();
String data = JSON.parseObject(json, new TypeReference() {}.getType());
dataList.add(data);
});
}
public void setWebsite(CrawlerWebsiteModelOut website) {
this.website = website;
}
public CrawlerWebsiteModelOut getWebsite() {
return website;
}
}
import com.alibaba.fastjson.JSONObject;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import com.lynn.yiyi.service.CrawlerService;
import com.lynn.yiyi.utils.SpringUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 爬虫动态代理类
*
* @author liyi
* @create 2018-03-17 18:22
**/
public class CrawlerCglibProxy implements MethodInterceptor {
private Map timerMap = new HashMap();
private Enhancer enhancer = new Enhancer();
Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object o = proxy.invokeSuper(obj,args);
if("start".equals(method.getName())){
if(args[0] instanceof CrawlerWebsiteModelOut){
CrawlerWebsiteModelOut website = (CrawlerWebsiteModelOut)args[0];
if(timerMap.get(website.getId()) == null){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
String data = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
String strs[] = website.getDataField().split("\\.");
for (String s : strs) {
JSONObject object = JSONObject.parseObject(data);
data = object.getString(s);
}
//TODO 这里将爬取到的数据写到数据库对应的表中
}
}, 0, website.getInterval());
timerMap.put(website.getId(),timer);
}
}
}
return o;
}
public static T create(Class cls){
CrawlerCglibProxy proxy = new CrawlerCglibProxy();
return (T)proxy.getProxy(cls);
}
}
import java.util.ArrayList;
import java.util.List;
/**
* 网站爬虫输出参数
*
* @author liyi
* @create 2018-03-17 17:04
**/
public class CrawlerWebsiteModelOut extends BaseModelOut {
private String url;
private Long interval;
private Integer websiteType;
private String websiteName;
private String sourceLink;
private String dataField;
private List contentList = new ArrayList();
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Long getInterval() {
return interval;
}
public void setInterval(Long interval) {
this.interval = interval;
}
public Integer getWebsiteType() {
return websiteType;
}
public void setWebsiteType(Integer websiteType) {
this.websiteType = websiteType;
}
public String getWebsiteName() {
return websiteName;
}
public void setWebsiteName(String websiteName) {
this.websiteName = websiteName;
}
public String getSourceLink() {
return sourceLink;
}
public void setSourceLink(String sourceLink) {
this.sourceLink = sourceLink;
}
public String getDataField() {
return dataField;
}
public void setDataField(String dataField) {
this.dataField = dataField;
}
public List getContentList() {
return contentList;
}
public void setContentList(List contentList) {
this.contentList = contentList;
}
}
/**
* 爬虫网站内容输出参数
*/
public class CrawlerWebsiteContentModelOut extends BaseModelOut{
private Long websiteId;
private String contentName;
private String tableName;
private String columnName;
private String returnField;
private Integer fieldType;
public Long getWebsiteId() {
return websiteId;
}
public void setWebsiteId(Long websiteId) {
this.websiteId = websiteId;
}
public String getContentName() {
return contentName;
}
public void setContentName(String contentName) {
this.contentName = contentName;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getReturnField() {
return returnField;
}
public void setReturnField(String returnField) {
this.returnField = returnField;
}
public Integer getFieldType() {
return fieldType;
}
public void setFieldType(Integer fieldType) {
this.fieldType = fieldType;
}
}
import java.util.Date;
/**
* 基础输出参数
*
* @author liyi
* @create 2018-03-17 17:02
**/
public abstract class BaseModelOut{
private Long id;
private Date create;
private Date modified;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getCreate() {
return create;
}
public void setCreate(Date create) {
this.create = create;
}
public Date getModified() {
return modified;
}
public void setModified(Date modified) {
this.modified = modified;
}
}
下面给出测试的主要方法
public static void main(String[] args) {
CrawlerProxy proxy = CrawlerFactory.create();
proxy.start(website);//website即当前要爬取的网站对象,可以从数据库中读取
}
调用main方法启动定时器,定时从指定网站爬取数据。
java爬虫抓取动态网页(爬虫+jsoup轻松爬知乎(一):爬虫语言之美)
网站优化 • 优采云 发表了文章 • 0 个评论 • 32 次浏览 • 2022-02-07 00:07
爬虫+jsoup轻松爬取知乎
爬知乎是用来测试和调试爬虫的,知乎非常容易爬。也建议初学者爬百度知道的知乎和网站。
最近对大数据很感兴趣,在写爬虫的同时也学习了Java。之前很少接触面向对象的编程语言,只有少量的VB基础。在了解了java之后,我发现了面向对象语言的美妙之处。(对于我这种只把编程当成爱好的鱼儿来说)java最美妙的地方就是有丰富的jar包可以调用,还有大神不断更新的jar包。和以前写C语言相比,每一行代码都是自己敲,现在写java,敲一个点,直接调用n个多功能函数,代码质量很高,简直是搬砖升级到摸腿又富又帅!
我一开始写的爬虫没有使用jsoup包。直接用java自带的httpconnect获取,使用parttern、matcher和正则语法过滤标签和元素。正则语法看起来很晕,parttern定义的模板通用性很差。做的爬虫整体代码比较冗长,完全没有代码的美感。
这次写的爬虫调用的是jsoup jar包。jsoup是一个优秀的HTML解析器,可以通过DOM、CSS以及类似jQuery的操作方法来检索和操作数据,并且封装了get方法,可以直接调用获取页面。结合谷歌浏览器抓取页面元素,快感不断。下面简单介绍一下用法。顺便说一句,我将发布 知乎climbing知乎 的代码。
jsoup包的导入就不说了。jsoup 使用的最重要的东西是元素类和 select() 方法。元素类相当于网页元素中的标签,通过select()方法根据一定的条件选择符合条件的标签,形成符合条件的标签数组。element 支持转换成字符串或文本等。总而言之,它非常强大。您只需要了解 select() 方法的过滤规则即可开始使用。但是使用谷歌浏览器!无需担心过滤规则,开始吧!
这是一个例子:
1.打开谷歌浏览器,在单机上右击要抓取的元素,比如我右击“Spring的JavaConfig Annotation文章”并选中勾选,自动跳出源码代码框,并定位到右击元素的位置。
2.右击代码行,复制-->复制选择器
3.这个时候,我们可以贴一下,看看我们复制了什么:
#div_JK > div.item_list > div:nth-child(1) > div.dTit.tracking-ad > a
表示目标在网页代码中的位置,前后每个>代表一个检索条件。然后我们要获取这个标签,只要写:
//下载网页
String URL="输入网址";
Document document=Jsoup.cnnect("URL");
//在下载的document里进行检索的语句
elements test=document.select("#div_JK")
.select("div.item_list").select("div:nth-child(1)").select("div.dTit.tracking-ad").select("a");
//这样test标签就是我们最开始右键单击检查的标签
String Str=test.toString();//将标签转化成字符串
String text=test.text();//将标签里的文本提取出来
//其他转换方法省略,检索到目标标签,提取标签里的特定元素so easy
贴出下面写的爬知乎的代码,网站比如知乎和贴吧都很适合爬。
目标是打印出 知乎 编辑建议的所有热门问题的 URL、问题名称、问题描述和答案。
代码块
简单的java爬虫代码:
package jsouptest;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class JsoupTest {
public static void main(String[] args) throws IOException {
//获取编辑推荐页
Document document=Jsoup.connect("https://www.zhihu.com/explore/recommendations")
//模拟火狐浏览器
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
.get();
Element main=document.getElementById("zh-recommend-list-full");
Elements url=main.select("div").select("div:nth-child(2)")
.select("h2").select("a[class=question_link]");
for(Element question:url){
//输出href后的值,即主页上每个关注问题的链接
String URL=question.attr("abs:href");
//下载问题链接指向的页面
Document document2=Jsoup.connect(URL)
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
.get();
//问题
Elements title=document2.select("#zh-question-title").select("h2").select("a");
//问题描述
Elements detail=document2.select("#zh-question-detail");
//回答
Elements answer=document2.select("#zh-question-answer-wrap")
.select("div.zm-item-rich-text.expandable.js-collapse-body")
.select("div.zm-editable-content.clearfix");
System.out.println("\n"+"链接:"+URL
+"\n"+"标题:"+title.text()
+"\n"+"问题描述:"+detail.text()
+"\n"+"回答:"+answer.text());
}
}
}
获取效果图:
eclipse编辑器不支持自动换行,所以文字堆积在一行。您可以使用文件类将捕获的数据存储在本地 txt 文件或 doc 文件中。
写爬虫的首要目标是抓取携程等机票数据。当然,不是为了大数据分析,而是为了我自己。大家都知道,机票最便宜的时间不是出发前一天,也不是出发前一个月,而是出发前十天或十天左右。此时,机票价格有一个低谷。因此,我想写一个机票爬虫并部署在服务器上,然后编写一个Android app将爬取目标传递给服务器,让爬虫爬取。爬的次数也不多,一天两三次就够了,也省了对反爬虫的研究。当车票进入预期价格或低谷时,只需发送消息通知我并手动购买车票。
是的,如果进展顺利,将有 3-4 次跟进文章,直到该项目完成。为了能多坐几趟航班见见我的小女朋友,祝你成功! 查看全部
java爬虫抓取动态网页(爬虫+jsoup轻松爬知乎(一):爬虫语言之美)
爬虫+jsoup轻松爬取知乎
爬知乎是用来测试和调试爬虫的,知乎非常容易爬。也建议初学者爬百度知道的知乎和网站。
最近对大数据很感兴趣,在写爬虫的同时也学习了Java。之前很少接触面向对象的编程语言,只有少量的VB基础。在了解了java之后,我发现了面向对象语言的美妙之处。(对于我这种只把编程当成爱好的鱼儿来说)java最美妙的地方就是有丰富的jar包可以调用,还有大神不断更新的jar包。和以前写C语言相比,每一行代码都是自己敲,现在写java,敲一个点,直接调用n个多功能函数,代码质量很高,简直是搬砖升级到摸腿又富又帅!
我一开始写的爬虫没有使用jsoup包。直接用java自带的httpconnect获取,使用parttern、matcher和正则语法过滤标签和元素。正则语法看起来很晕,parttern定义的模板通用性很差。做的爬虫整体代码比较冗长,完全没有代码的美感。
这次写的爬虫调用的是jsoup jar包。jsoup是一个优秀的HTML解析器,可以通过DOM、CSS以及类似jQuery的操作方法来检索和操作数据,并且封装了get方法,可以直接调用获取页面。结合谷歌浏览器抓取页面元素,快感不断。下面简单介绍一下用法。顺便说一句,我将发布 知乎climbing知乎 的代码。
jsoup包的导入就不说了。jsoup 使用的最重要的东西是元素类和 select() 方法。元素类相当于网页元素中的标签,通过select()方法根据一定的条件选择符合条件的标签,形成符合条件的标签数组。element 支持转换成字符串或文本等。总而言之,它非常强大。您只需要了解 select() 方法的过滤规则即可开始使用。但是使用谷歌浏览器!无需担心过滤规则,开始吧!
这是一个例子:
1.打开谷歌浏览器,在单机上右击要抓取的元素,比如我右击“Spring的JavaConfig Annotation文章”并选中勾选,自动跳出源码代码框,并定位到右击元素的位置。
2.右击代码行,复制-->复制选择器
3.这个时候,我们可以贴一下,看看我们复制了什么:
#div_JK > div.item_list > div:nth-child(1) > div.dTit.tracking-ad > a
表示目标在网页代码中的位置,前后每个>代表一个检索条件。然后我们要获取这个标签,只要写:
//下载网页
String URL="输入网址";
Document document=Jsoup.cnnect("URL");
//在下载的document里进行检索的语句
elements test=document.select("#div_JK")
.select("div.item_list").select("div:nth-child(1)").select("div.dTit.tracking-ad").select("a");
//这样test标签就是我们最开始右键单击检查的标签
String Str=test.toString();//将标签转化成字符串
String text=test.text();//将标签里的文本提取出来
//其他转换方法省略,检索到目标标签,提取标签里的特定元素so easy
贴出下面写的爬知乎的代码,网站比如知乎和贴吧都很适合爬。
目标是打印出 知乎 编辑建议的所有热门问题的 URL、问题名称、问题描述和答案。
代码块
简单的java爬虫代码:
package jsouptest;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class JsoupTest {
public static void main(String[] args) throws IOException {
//获取编辑推荐页
Document document=Jsoup.connect("https://www.zhihu.com/explore/recommendations")
//模拟火狐浏览器
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
.get();
Element main=document.getElementById("zh-recommend-list-full");
Elements url=main.select("div").select("div:nth-child(2)")
.select("h2").select("a[class=question_link]");
for(Element question:url){
//输出href后的值,即主页上每个关注问题的链接
String URL=question.attr("abs:href");
//下载问题链接指向的页面
Document document2=Jsoup.connect(URL)
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
.get();
//问题
Elements title=document2.select("#zh-question-title").select("h2").select("a");
//问题描述
Elements detail=document2.select("#zh-question-detail");
//回答
Elements answer=document2.select("#zh-question-answer-wrap")
.select("div.zm-item-rich-text.expandable.js-collapse-body")
.select("div.zm-editable-content.clearfix");
System.out.println("\n"+"链接:"+URL
+"\n"+"标题:"+title.text()
+"\n"+"问题描述:"+detail.text()
+"\n"+"回答:"+answer.text());
}
}
}
获取效果图:
eclipse编辑器不支持自动换行,所以文字堆积在一行。您可以使用文件类将捕获的数据存储在本地 txt 文件或 doc 文件中。
写爬虫的首要目标是抓取携程等机票数据。当然,不是为了大数据分析,而是为了我自己。大家都知道,机票最便宜的时间不是出发前一天,也不是出发前一个月,而是出发前十天或十天左右。此时,机票价格有一个低谷。因此,我想写一个机票爬虫并部署在服务器上,然后编写一个Android app将爬取目标传递给服务器,让爬虫爬取。爬的次数也不多,一天两三次就够了,也省了对反爬虫的研究。当车票进入预期价格或低谷时,只需发送消息通知我并手动购买车票。
是的,如果进展顺利,将有 3-4 次跟进文章,直到该项目完成。为了能多坐几趟航班见见我的小女朋友,祝你成功!
java爬虫抓取动态网页( 动态网页爬虫技术一之API请求法安装selenium模块下载(组图))
网站优化 • 优采云 发表了文章 • 0 个评论 • 53 次浏览 • 2022-02-06 19:13
动态网页爬虫技术一之API请求法安装selenium模块下载(组图))
本节课我给大家讲解一个稍微复杂一点的爬虫,也就是动态网页的爬虫。
动态网页技术简介
动态网络爬虫技术的API请求方法
动态网络爬虫技术二:模拟浏览器方法
安装 selenium 模块下载
谷歌浏览器驱动安装
ChromeDriver以某宝藏松鼠店为例,抓取“坚果炒货”的商品名称、价格、销量和评论数
课后作业
关于作者
动态网页技术简介
所谓动态网页,是指相对于静态网页的一种网页编程技术。对于静态网页,随着html代码的生成,页面的内容和显示效果基本不会改变——除非你修改了页面代码。动态网页并非如此。虽然页面代码没有改变,但是显示的内容会随着时间、环境或数据库操作的结果而改变。
值得强调的是,动态网页不应与页面内容是否动态相混淆。这里所说的动态网页与网页上的各种动画、滚动字幕等视觉动态效果没有直接关系。动态网页也可以是纯文本内容或收录各种动画内容。这些只是特定于网页。内容的呈现形式,无论网页是否具有动态效果,只要是通过动态网站技术生成的,都可以称为动态网页。(说明来源:百度百科-《动态网页》,如链接失效请访问:%E5%8A%A8%E6%80%81%E7%BD%91%E9%A1%B5/6327050?fr=阿拉丁)
互联网每天都在蓬勃发展,数以万计的网络平台雨后春笋般涌现。不同平台针对不同用户的权限和偏好推出不同的个性化内容。看来,传统的静态网页早已无法满足社会的需求。于是,动态网页技术应运而生。当然,在对网页加载速度要求越来越高的情况下,异步加载成为了很多大型网站的首选。比如各大电商平台、知识型网站、社交平台等,都广泛采用了异步加载的动态技术。简单来说就是加载一些根据时间和请求变化的内容,比如某宝的商品价格和评论,比如某阀门的热门影评,某条新闻的视频等,通过先加载网页整体框架,再加载。呈现动态内容。
对于这种类型的动态页面,如果我们使用上面提到的静态网页爬虫的方法来爬取,可能不会得到任何结果,因为大部分异步加载的内容都位于请求该内容的一段JS代码中。在一定的触发操作下,这些JS代码开始工作,从数据库中提取相应的数据,放到网页框架中的相应位置,最后拼接成一个我们可以看到的完整页面。
动态网络爬虫技术的API请求方法
看似复杂的操作,看似给我们的爬虫带来了不少麻烦,但其实也可能给我们带来很大的方便。我们只需要找到JS请求的API,按照一定的要求发送带有有效参数的请求,就可以得到最干净的数据,而不是像以前那样从嵌套的HTML代码中慢慢解析出我们想要的HTML代码。所需的数据。
这里我们以上面提到的豆瓣电影(如果链接失效请访问:#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0)为例进行制作分析,提取豆瓣前100名电影的名称和评分及其地址。
这是按人气排序的近期热门电影的截图。每个月都有不同的新电影上映,每部电影都会因为口碑效应而呈现出不同的热度排名。如果这个页面是静态网页,那么豆瓣程序员每天上网修改这个页面是不是很辛苦。所以,我们可以大胆猜测这是一个动态页面。但猜测是不够的,我们必须证明它。这里我们将使用第二讲中提到的谷歌开发者工具。按F12或者在网页空白处右键选择Inspect(N),或者按键盘上的组合键Ctrl+Shift+I来召唤我们的神器。如下所示:
今天我们不再使用左上角的鼠标按钮,而是使用红色框中的Network,显示了网页加载的所有文件,如下图所示:
如果下面没有结果,您需要在打开 Google Developer Tools 的情况下刷新页面。
如上图所示,我们可以通过点击上方小红框内的“XHR”按钮来过滤这个网页中异步加载的内容。至于哪一个是我们想要的,这是一个问题。看左边的地址,我们好像看不出什么端倪,我们来一一看看吧。. . 经过枚举,我们发现第三个就是我们想要的内容,其内容如下:
我们可以看到这个链接中收录的内容是以 JSON 格式显示的。这时候我们就有了一个大概的思路,就是用requests模块下载这个链接的内容,然后用python的json模块下载内容。解析。
但是,这似乎是一页,并且只有 20 部电影要数,而我们要的是前 100 部电影,如何做到这一点?
没办法,毕竟是动态网页,内容可以根据请求改变,而且这里也没有登录操作,打开网页就可以看到,那我们可以换个网址来获取到下一页甚至下一页 页面的内容?当然可以,不然我就写不出来了!
让我们仔细看看这个 URL 中传递的参数:
至此,我们可能不知道这五个参数是干什么用的,但是我们可以找到规律,所以现在回到原来的网页,点击页面底部的“加载更多”,然后返回给开发者工具,哇,多了一个网址,就是刚才说的那个,内容也只要:
此 URL 还传递五个参数:
唯一的区别是名为“page_start”的关键字的值发生了变化。简单地把它翻译成页面的起点。看上面的“page_limit”,大概就是页数限制的意思。看右边的响应内容,这个页面传递了20个条目,也就是说“page_limit”是一个页面的条目数限制,也就是20,这个数据不变,而“page_start”是本页开头的条目号,那么我们要获取下面的内容,改“page_start”不就够了吗?是的。
老规矩,先写个代码
# -*- coding: utf-8 -*-
import requests
import jsonfor i in range(5):
page_start = str(i * 20) # 注释1
url = 'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=' + page_start # 注释2
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}
response = requests.get(url=url, headers=headers, verify=False)
content = response.content.decode()
content_list = json.loads(content)['subjects'] # 注释3for item in content_list: # 注释4
title = item['title'] #注释5
rate = item['rate'] # 注释6
link = item['url'] # 注释7
print(title, rate, link)
最后,可以使用标准输入流写入txt文件,也可以使用xlwt模块写入EXCEL,也可以使用pymysql模块写入Mysql数据库。
至此,这种寻找API并传递有效参数重放API的方法已经介绍给大家了。这是一种很常用的方法,可以在很多网站中使用,而且速度非常快,结果也是最简洁的。.
动态网络爬虫技术二:模拟浏览器方法
虽然我们上面提到的API请求方式好用又快,但并不是所有的网站都会使用这种异步加载方式来实现网站,还有一些网站会采取反爬措施爬虫,比如常见的验证码。虽然验证码主要是用来防止CSRF攻击的,但也有网站用来对付爬虫的,比如某宝。这时候我们要介绍另一个神器,Python的Selenium模块。
Selenium 是用于 Web 应用程序测试的工具。Selenium 测试直接在浏览器中运行,就像真正的用户一样。支持的浏览器包括 IE (7, 8, 9, 10, 11), Mozilla Firefox, Safari, Google Chrome, Opera等。该工具的主要功能包括: 测试与浏览器的兼容性 - 测试看看你的应用程序是否(解释来自:百度百科-“Selenium”,如果链接失效请点击)
简单来说,Selenium 是一个主要用于自动化测试的工具。它可以运行在各种带有浏览器驱动程序的浏览器中,并根据代码自动模拟人类操作来获取或控制网页元素。当然,Selenium 不是 Python 的产品,而是一个独立的项目,Python 提供了对 Selenium 的支持。(您可以自行访问 Selenium 的主页,如果链接无效,请点击)
安装硒模块
要使用Selenium这样的第三方工具,我们首先要安装它,这里还是使用pip工具。以管理员权限运行命令行,输入pip install selenium,稍等片刻即可完成安装,如果觉得官方pypi镜像网速慢,可以使用国内豆瓣镜像源,pip install selenium -i ,加上这个 -i 参数和豆瓣pypi镜像的地址就够了。如果要默认使用豆瓣镜像源,请自行百度修改方法。
下载谷歌浏览器驱动
安装成功后,我们需要安装下一个必要的东西,浏览器驱动程序。前面提到,selenium 需要配合浏览器驱动运行,所以我们以安装 Google Chrome Driver 为例。
首先,我们需要查看我们的谷歌浏览器版本,可以在谷歌的“帮助”中查看。具体方法是打开Chrome,点击右上角的三个点状按钮,然后在弹出的菜单中依次选择Help。(E)->关于谷歌浏览器(G)如下图:
笔者的浏览器更新到最新版本63,老版本的操作方法大致相同。
点击信息后,我们可以看到当前的Chrome版本,下图为示例:
Chrome在不断的升级,所以相应的驱动也要不断的更新和适配Chrome的版本。这里我们需要找到对应的ChromeDriver版本映射,推荐一个持续更新的CSDN博客(如果链接失效请点击:),根据版本映射表,下载对应版本的ChromeDriver,下载地址1()(如果链接失效,请访问:),下载地址2()(如果链接失效,请访问:)。
安装 ChromeDriver
这里需要配置环境变量。正如第一讲中提到的,为“路径”添加一行值。
首先,我们需要找到 Chrome 的安装位置。最简单的方法是在桌面上找到谷歌浏览器的快捷方式,右键单击并选择“打开文件的位置”将其打开。比如我这里打开的路径是C:\Program Files(x86)\Google\Chrome\Application,那我就把这个路径加到Path里面。然后,我们需要把下载的ChromeDriver解压到exe程序中,将单独的exe程序复制到刚才的路径下,如下图:
至此,ChromeDriver 已经完成安装。我们可以在命令行输入命令python进入python交互环境进行测试,如下图所示:
如果你的谷歌浏览器自动打开并跳转到百度首页,那么恭喜~
以某宝的松鼠店为例,抓取“坚果炒货”的品名、价格、销量和评论数
此页面的 URL 是:#TmshopSrchNav
老规矩,先放一段代码:
# -*- coding: utf-8 -*-
from selenium import webdriver
driver = webdriver.Chrome() # 注释1
url = 'https://sanzhisongshu.tmall.com/category-1124487841.htm?spm=a1z10.1-b-s.w5003-17763072511.42.6995d6732XB8Of&tsearch=y&scene=taobao_shop#TmshopSrchNav'
driver.maximize_window() # 注释2
driver.get(url) # 注释3
dl_list = driver.find_elements_by_class_name('item') # 注释4
for dl in dl_list:
name = dl.find_element_by_css_selector("[class='item-name J_TGoldData']").text # 注释5
price = dl.find_element_by_class_name('cprice-area').text # 注释6
sale = dl.find_element_by_class_name('sale-area').text # 注释7
comment = dl.find_element_by_xpath('//*[@id="J_ShopSearchResult"]/div/div[3]/div[1]/dl[1]/dd[2]/div/h4/a/span').text # 注释8
print(name, price, sale, comment)
driver.close() # 注释9
XPath 代表 XML 路径语言,它是一种用于定位 XML(标准通用标记语言的子集)文档部分的语言。XPath 基于 XML 树结构,有不同类型的节点,包括元素节点、属性节点和文本节点,提供了在数据结构树中查找节点的能力。XPath 的初衷是将其用作 XPointer 和 XSLT 之间的通用语法模型。但是 XPath 作为一种小型查询语言很快被开发人员采用。(解释来自:百度百科-《XPath》,如果链接失效请访问:)
这个例子的最终结果如下:
您仍然可以自由选择数据存储方式。
这里需要注意的是,使用 selenium 进行数据爬取可能比之前的 API 请求方式慢很多。打开到对应的窗口后,窗口可能会长时间没有动作,但这不一定是错误或者是程序卡住的表现,也可能是程序在疯狂搜索网页元素. 在此过程中,如果您不确定是否有错误,请不要进行其他操作,以免有时导致元素失去焦点,导致莫名其妙的错误。
当然,硒的作用远不止这些。它几乎可以模拟人们在网页上可以做的任何行为,包括点击、输入等行为。这个比较适合一些网站填写验证码的你可以自己发现更多有趣的内容。本次讲座写在这里。感谢大家的耐心阅读。
课后作业
这是给你的两个小任务。有兴趣的可以自行测试。
请使用API请求方式在QQ音乐上自行查找歌曲下载,无需登录账号即可下载歌曲。请使用selenium爬取知乎热门话题或话题的首页回答100。
关于作者
作者是一名即将毕业的大四学生。他自学爬虫,是几个爬虫项目的主要开发者。对各种爬虫有一定的了解和项目经验。为大家更新。作者也是一个狂热的信息安全爱好者。谢谢你的支持。 查看全部
java爬虫抓取动态网页(
动态网页爬虫技术一之API请求法安装selenium模块下载(组图))
本节课我给大家讲解一个稍微复杂一点的爬虫,也就是动态网页的爬虫。
动态网页技术简介
动态网络爬虫技术的API请求方法
动态网络爬虫技术二:模拟浏览器方法
安装 selenium 模块下载
谷歌浏览器驱动安装
ChromeDriver以某宝藏松鼠店为例,抓取“坚果炒货”的商品名称、价格、销量和评论数
课后作业
关于作者
动态网页技术简介
所谓动态网页,是指相对于静态网页的一种网页编程技术。对于静态网页,随着html代码的生成,页面的内容和显示效果基本不会改变——除非你修改了页面代码。动态网页并非如此。虽然页面代码没有改变,但是显示的内容会随着时间、环境或数据库操作的结果而改变。
值得强调的是,动态网页不应与页面内容是否动态相混淆。这里所说的动态网页与网页上的各种动画、滚动字幕等视觉动态效果没有直接关系。动态网页也可以是纯文本内容或收录各种动画内容。这些只是特定于网页。内容的呈现形式,无论网页是否具有动态效果,只要是通过动态网站技术生成的,都可以称为动态网页。(说明来源:百度百科-《动态网页》,如链接失效请访问:%E5%8A%A8%E6%80%81%E7%BD%91%E9%A1%B5/6327050?fr=阿拉丁)
互联网每天都在蓬勃发展,数以万计的网络平台雨后春笋般涌现。不同平台针对不同用户的权限和偏好推出不同的个性化内容。看来,传统的静态网页早已无法满足社会的需求。于是,动态网页技术应运而生。当然,在对网页加载速度要求越来越高的情况下,异步加载成为了很多大型网站的首选。比如各大电商平台、知识型网站、社交平台等,都广泛采用了异步加载的动态技术。简单来说就是加载一些根据时间和请求变化的内容,比如某宝的商品价格和评论,比如某阀门的热门影评,某条新闻的视频等,通过先加载网页整体框架,再加载。呈现动态内容。
对于这种类型的动态页面,如果我们使用上面提到的静态网页爬虫的方法来爬取,可能不会得到任何结果,因为大部分异步加载的内容都位于请求该内容的一段JS代码中。在一定的触发操作下,这些JS代码开始工作,从数据库中提取相应的数据,放到网页框架中的相应位置,最后拼接成一个我们可以看到的完整页面。
动态网络爬虫技术的API请求方法
看似复杂的操作,看似给我们的爬虫带来了不少麻烦,但其实也可能给我们带来很大的方便。我们只需要找到JS请求的API,按照一定的要求发送带有有效参数的请求,就可以得到最干净的数据,而不是像以前那样从嵌套的HTML代码中慢慢解析出我们想要的HTML代码。所需的数据。
这里我们以上面提到的豆瓣电影(如果链接失效请访问:#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0)为例进行制作分析,提取豆瓣前100名电影的名称和评分及其地址。
这是按人气排序的近期热门电影的截图。每个月都有不同的新电影上映,每部电影都会因为口碑效应而呈现出不同的热度排名。如果这个页面是静态网页,那么豆瓣程序员每天上网修改这个页面是不是很辛苦。所以,我们可以大胆猜测这是一个动态页面。但猜测是不够的,我们必须证明它。这里我们将使用第二讲中提到的谷歌开发者工具。按F12或者在网页空白处右键选择Inspect(N),或者按键盘上的组合键Ctrl+Shift+I来召唤我们的神器。如下所示:
今天我们不再使用左上角的鼠标按钮,而是使用红色框中的Network,显示了网页加载的所有文件,如下图所示:
如果下面没有结果,您需要在打开 Google Developer Tools 的情况下刷新页面。
如上图所示,我们可以通过点击上方小红框内的“XHR”按钮来过滤这个网页中异步加载的内容。至于哪一个是我们想要的,这是一个问题。看左边的地址,我们好像看不出什么端倪,我们来一一看看吧。. . 经过枚举,我们发现第三个就是我们想要的内容,其内容如下:
我们可以看到这个链接中收录的内容是以 JSON 格式显示的。这时候我们就有了一个大概的思路,就是用requests模块下载这个链接的内容,然后用python的json模块下载内容。解析。
但是,这似乎是一页,并且只有 20 部电影要数,而我们要的是前 100 部电影,如何做到这一点?
没办法,毕竟是动态网页,内容可以根据请求改变,而且这里也没有登录操作,打开网页就可以看到,那我们可以换个网址来获取到下一页甚至下一页 页面的内容?当然可以,不然我就写不出来了!
让我们仔细看看这个 URL 中传递的参数:
至此,我们可能不知道这五个参数是干什么用的,但是我们可以找到规律,所以现在回到原来的网页,点击页面底部的“加载更多”,然后返回给开发者工具,哇,多了一个网址,就是刚才说的那个,内容也只要:
此 URL 还传递五个参数:
唯一的区别是名为“page_start”的关键字的值发生了变化。简单地把它翻译成页面的起点。看上面的“page_limit”,大概就是页数限制的意思。看右边的响应内容,这个页面传递了20个条目,也就是说“page_limit”是一个页面的条目数限制,也就是20,这个数据不变,而“page_start”是本页开头的条目号,那么我们要获取下面的内容,改“page_start”不就够了吗?是的。
老规矩,先写个代码
# -*- coding: utf-8 -*-
import requests
import jsonfor i in range(5):
page_start = str(i * 20) # 注释1
url = 'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=' + page_start # 注释2
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}
response = requests.get(url=url, headers=headers, verify=False)
content = response.content.decode()
content_list = json.loads(content)['subjects'] # 注释3for item in content_list: # 注释4
title = item['title'] #注释5
rate = item['rate'] # 注释6
link = item['url'] # 注释7
print(title, rate, link)
最后,可以使用标准输入流写入txt文件,也可以使用xlwt模块写入EXCEL,也可以使用pymysql模块写入Mysql数据库。
至此,这种寻找API并传递有效参数重放API的方法已经介绍给大家了。这是一种很常用的方法,可以在很多网站中使用,而且速度非常快,结果也是最简洁的。.
动态网络爬虫技术二:模拟浏览器方法
虽然我们上面提到的API请求方式好用又快,但并不是所有的网站都会使用这种异步加载方式来实现网站,还有一些网站会采取反爬措施爬虫,比如常见的验证码。虽然验证码主要是用来防止CSRF攻击的,但也有网站用来对付爬虫的,比如某宝。这时候我们要介绍另一个神器,Python的Selenium模块。
Selenium 是用于 Web 应用程序测试的工具。Selenium 测试直接在浏览器中运行,就像真正的用户一样。支持的浏览器包括 IE (7, 8, 9, 10, 11), Mozilla Firefox, Safari, Google Chrome, Opera等。该工具的主要功能包括: 测试与浏览器的兼容性 - 测试看看你的应用程序是否(解释来自:百度百科-“Selenium”,如果链接失效请点击)
简单来说,Selenium 是一个主要用于自动化测试的工具。它可以运行在各种带有浏览器驱动程序的浏览器中,并根据代码自动模拟人类操作来获取或控制网页元素。当然,Selenium 不是 Python 的产品,而是一个独立的项目,Python 提供了对 Selenium 的支持。(您可以自行访问 Selenium 的主页,如果链接无效,请点击)
安装硒模块
要使用Selenium这样的第三方工具,我们首先要安装它,这里还是使用pip工具。以管理员权限运行命令行,输入pip install selenium,稍等片刻即可完成安装,如果觉得官方pypi镜像网速慢,可以使用国内豆瓣镜像源,pip install selenium -i ,加上这个 -i 参数和豆瓣pypi镜像的地址就够了。如果要默认使用豆瓣镜像源,请自行百度修改方法。
下载谷歌浏览器驱动
安装成功后,我们需要安装下一个必要的东西,浏览器驱动程序。前面提到,selenium 需要配合浏览器驱动运行,所以我们以安装 Google Chrome Driver 为例。
首先,我们需要查看我们的谷歌浏览器版本,可以在谷歌的“帮助”中查看。具体方法是打开Chrome,点击右上角的三个点状按钮,然后在弹出的菜单中依次选择Help。(E)->关于谷歌浏览器(G)如下图:
笔者的浏览器更新到最新版本63,老版本的操作方法大致相同。
点击信息后,我们可以看到当前的Chrome版本,下图为示例:
Chrome在不断的升级,所以相应的驱动也要不断的更新和适配Chrome的版本。这里我们需要找到对应的ChromeDriver版本映射,推荐一个持续更新的CSDN博客(如果链接失效请点击:),根据版本映射表,下载对应版本的ChromeDriver,下载地址1()(如果链接失效,请访问:),下载地址2()(如果链接失效,请访问:)。
安装 ChromeDriver
这里需要配置环境变量。正如第一讲中提到的,为“路径”添加一行值。
首先,我们需要找到 Chrome 的安装位置。最简单的方法是在桌面上找到谷歌浏览器的快捷方式,右键单击并选择“打开文件的位置”将其打开。比如我这里打开的路径是C:\Program Files(x86)\Google\Chrome\Application,那我就把这个路径加到Path里面。然后,我们需要把下载的ChromeDriver解压到exe程序中,将单独的exe程序复制到刚才的路径下,如下图:
至此,ChromeDriver 已经完成安装。我们可以在命令行输入命令python进入python交互环境进行测试,如下图所示:
如果你的谷歌浏览器自动打开并跳转到百度首页,那么恭喜~
以某宝的松鼠店为例,抓取“坚果炒货”的品名、价格、销量和评论数
此页面的 URL 是:#TmshopSrchNav
老规矩,先放一段代码:
# -*- coding: utf-8 -*-
from selenium import webdriver
driver = webdriver.Chrome() # 注释1
url = 'https://sanzhisongshu.tmall.com/category-1124487841.htm?spm=a1z10.1-b-s.w5003-17763072511.42.6995d6732XB8Of&tsearch=y&scene=taobao_shop#TmshopSrchNav'
driver.maximize_window() # 注释2
driver.get(url) # 注释3
dl_list = driver.find_elements_by_class_name('item') # 注释4
for dl in dl_list:
name = dl.find_element_by_css_selector("[class='item-name J_TGoldData']").text # 注释5
price = dl.find_element_by_class_name('cprice-area').text # 注释6
sale = dl.find_element_by_class_name('sale-area').text # 注释7
comment = dl.find_element_by_xpath('//*[@id="J_ShopSearchResult"]/div/div[3]/div[1]/dl[1]/dd[2]/div/h4/a/span').text # 注释8
print(name, price, sale, comment)
driver.close() # 注释9
XPath 代表 XML 路径语言,它是一种用于定位 XML(标准通用标记语言的子集)文档部分的语言。XPath 基于 XML 树结构,有不同类型的节点,包括元素节点、属性节点和文本节点,提供了在数据结构树中查找节点的能力。XPath 的初衷是将其用作 XPointer 和 XSLT 之间的通用语法模型。但是 XPath 作为一种小型查询语言很快被开发人员采用。(解释来自:百度百科-《XPath》,如果链接失效请访问:)
这个例子的最终结果如下:
您仍然可以自由选择数据存储方式。
这里需要注意的是,使用 selenium 进行数据爬取可能比之前的 API 请求方式慢很多。打开到对应的窗口后,窗口可能会长时间没有动作,但这不一定是错误或者是程序卡住的表现,也可能是程序在疯狂搜索网页元素. 在此过程中,如果您不确定是否有错误,请不要进行其他操作,以免有时导致元素失去焦点,导致莫名其妙的错误。
当然,硒的作用远不止这些。它几乎可以模拟人们在网页上可以做的任何行为,包括点击、输入等行为。这个比较适合一些网站填写验证码的你可以自己发现更多有趣的内容。本次讲座写在这里。感谢大家的耐心阅读。
课后作业
这是给你的两个小任务。有兴趣的可以自行测试。
请使用API请求方式在QQ音乐上自行查找歌曲下载,无需登录账号即可下载歌曲。请使用selenium爬取知乎热门话题或话题的首页回答100。
关于作者
作者是一名即将毕业的大四学生。他自学爬虫,是几个爬虫项目的主要开发者。对各种爬虫有一定的了解和项目经验。为大家更新。作者也是一个狂热的信息安全爱好者。谢谢你的支持。
java爬虫抓取动态网页(教您使用java爬虫geccogeccoJD商品信息商品信息)
网站优化 • 优采云 发表了文章 • 0 个评论 • 48 次浏览 • 2022-02-06 17:23
关于gecco爬虫框架
不了解gecco的可以参考gecco的github主页。gecco 爬虫非常简单易用。有一篇文章文章《教你使用java爬虫gecco抓取京东商品信息》,使用的是传统的注解方式。建议在阅读本文章之前先了解前面的文章。这里我们介绍一下DynamicGecco方法,它比以前更简单。只需要3个品类,就可以把京东的所有产品都抢完。
什么是 DynamicGecco
DynamicGecco的目的是在不定义SpiderBeans的情况下实现爬取规则的运行时配置。实现原理是利用字节码编程动态生成SpiderBeans,通过自定义的GeccoClassLoader实现抓取规则的热部署。通常我们可以使用DynamicGecco来实现以下功能:
规则定义
爬虫的爬取规则,如matchUrl、csspath、ajax等,不需要使用注解注入SpiderBean,直接使用DynamicGecco定义。以下是京东全品抓取规则定义:
public static void main(String[] args) {
//对应原来的Category和HrefBean类
Class category = DynamicGecco.html
.stringField("parentName").csspath("dt a").text.build
.listField("categorys",
DynamicGecco.html
.stringField("url").csspath("a").href.build
.stringField("title").csspath("a").text.build
.register).csspath("dd a").build
.register;
//对应原来的AllSort类
DynamicGecco.html
.gecco("http://www.jd.com/allSort.aspx", "consolePipeline", "allSortJsonPipeline")
.requestField("request").request.build
.listField("mobile", category)
.csspath(".category-items > div:nth-child(1) > div:nth-child(2) > div.mc > div.items > dl").build
.register;
//对应ProductBrief类
Class productBrief = DynamicGecco.html
.stringField("code").csspath(".j-sku-item").attr("data-sku").build
.stringField("title").csspath(".p-name> a > em").text.build
.stringField("preview").csspath(".p-img > a > img").image("", "data-lazy-img", "src").build
.stringField("detailUrl").csspath(".p-name > a").href(true).build
.register;
//对应ProductList类
DynamicGecco.html
.gecco("http://list.jd.com/list.html?cat={cat}&delivery={delivery}&page={page}&JL={JL}&go=0", "consolePipeline", "productListJsonPipeline")
.requestField("request").request.build
.intField("currPage").csspath("#J_topPage > span > b").text.build
.intField("totalPage").csspath("#J_topPage > span > i").text.build
.listField("details", productBrief).csspath("#plist .gl-item").build
.register;
//对应ProductDetail类
DynamicGecco.html
.gecco("http://item.jd.com/{code}.html", "consolePipeline")
.stringField("code").requestParameter.build
.stringField("title").csspath("#name > h1").text.build
.stringField("detail").csspath("#product-detail-2").build
.stringField("image").csspath("#spec-n1 img").image("d:/gecco/jd/img").build
.field("price", FieldType.type(JDPrice.class)).ajax("http://p.3.cn/prices/get%3Ftyp ... %3DJ_{code}").build
.field("jdAd", FieldType.type(JDad.class)).ajax("http://cd.jd.com/promotion/v2?skuId={code}&area=1_2805_2855_0&cat=737%2C794%2C798").build
.register;
HttpGetRequest start = new HttpGetRequest("http://www.jd.com/allSort.aspx");
start.setCharset("GBK");
GeccoEngine.create
.classpath("com.geccocrawler.gecco.demo.jd")
.start(start)
.interval(2000)
.run;
}
规则定义好后,就可以启动GeccoEngine了,和之前一样。可以看出,前面的例子定义了7个bean,但是这里只需要一个类。
语法解释 JsonPipeline
Pipeline 的写法也和以前不一样。因为是运行时生成的bean,所以定义的bean不能像以前那样直接使用。Gecco 会将所有 bean 转换为 JSONObject,并通过 json 操作获取捕获的信息。下面是DynamicJD定义的两条Pipeline:
@PipelineName("allSortJsonPipeline")
public class AllSortJsonPipeline extends JsonPipeline {
public static List sortRequests = new ArrayList;
@Override
public void process(JSONObject allSort) {
HttpRequest currRequest = HttpGetRequest.fromJson(allSort.getJSONObject("request"));
JSONArray categorys = allSort.getJSONArray("mobile");
process(currRequest, categorys);
}
private void process(HttpRequest currRequest, JSONArray categorys) {
if(categorys == null) {
return;
}
for(int i = 0; i < categorys.size; i++) {
JSONObject category = categorys.getJSONObject(i);
JSONArray hrefs = category.getJSONArray("categorys");
for(int j = 0; j < hrefs.size; j++) {
String url = hrefs.getJSONObject(j).getString("url")+"&delivery=1&page=1&JL=4_10_0&go=0";
SchedulerContext.into(currRequest.subRequest(url));
}
}
}
}
产品列表处理Pipeline,对应原ProductListPipeline
@PipelineName("productListPipeline")
public class ProductListPipeline implements Pipeline {
@Override
public void process(ProductList productList) {
HttpRequest currRequest = productList.getRequest;
//下一页继续抓取
int currPage = productList.getCurrPage;
int nextPage = currPage + 1;
int totalPage = productList.getTotalPage;
if(nextPage newRule = DynamicGecco
.html(rule1.getName)
.gecco("https://github.com/xtuhcy/gecco", "consolePipeline")
.intField("fork").csspath(".pagehead-actions li:nth-child(3) .social-count").text.build
.removeField("star")
.loadClass;
//注册新规则
ge.register(newRule);
} catch(Exception ex) {
ex.printStackTrace;
} finally {
//规则更新完毕
ge.endUpdateRule;
}
线下有规矩
已经定义好的规则,我们可以下线如下:
try {
//开始更新规则
ge.beginUpdateRule;
//下线之前的规则
ge.unregister(rule);
} catch(Exception ex) {
ex.printStackTrace;
} finally {
//规则更新完毕
ge.endUpdateRule;
}
至此,爬虫规则的添加/修改/删除已经实现。您可以愉快地配置爬虫规则!
完整的demo代码可以参考github上的源码,位于com.geccocrawler.gecco.demo.dynamic包中。 查看全部
java爬虫抓取动态网页(教您使用java爬虫geccogeccoJD商品信息商品信息)
关于gecco爬虫框架
不了解gecco的可以参考gecco的github主页。gecco 爬虫非常简单易用。有一篇文章文章《教你使用java爬虫gecco抓取京东商品信息》,使用的是传统的注解方式。建议在阅读本文章之前先了解前面的文章。这里我们介绍一下DynamicGecco方法,它比以前更简单。只需要3个品类,就可以把京东的所有产品都抢完。
什么是 DynamicGecco
DynamicGecco的目的是在不定义SpiderBeans的情况下实现爬取规则的运行时配置。实现原理是利用字节码编程动态生成SpiderBeans,通过自定义的GeccoClassLoader实现抓取规则的热部署。通常我们可以使用DynamicGecco来实现以下功能:
规则定义
爬虫的爬取规则,如matchUrl、csspath、ajax等,不需要使用注解注入SpiderBean,直接使用DynamicGecco定义。以下是京东全品抓取规则定义:
public static void main(String[] args) {
//对应原来的Category和HrefBean类
Class category = DynamicGecco.html
.stringField("parentName").csspath("dt a").text.build
.listField("categorys",
DynamicGecco.html
.stringField("url").csspath("a").href.build
.stringField("title").csspath("a").text.build
.register).csspath("dd a").build
.register;
//对应原来的AllSort类
DynamicGecco.html
.gecco("http://www.jd.com/allSort.aspx", "consolePipeline", "allSortJsonPipeline")
.requestField("request").request.build
.listField("mobile", category)
.csspath(".category-items > div:nth-child(1) > div:nth-child(2) > div.mc > div.items > dl").build
.register;
//对应ProductBrief类
Class productBrief = DynamicGecco.html
.stringField("code").csspath(".j-sku-item").attr("data-sku").build
.stringField("title").csspath(".p-name> a > em").text.build
.stringField("preview").csspath(".p-img > a > img").image("", "data-lazy-img", "src").build
.stringField("detailUrl").csspath(".p-name > a").href(true).build
.register;
//对应ProductList类
DynamicGecco.html
.gecco("http://list.jd.com/list.html?cat={cat}&delivery={delivery}&page={page}&JL={JL}&go=0", "consolePipeline", "productListJsonPipeline")
.requestField("request").request.build
.intField("currPage").csspath("#J_topPage > span > b").text.build
.intField("totalPage").csspath("#J_topPage > span > i").text.build
.listField("details", productBrief).csspath("#plist .gl-item").build
.register;
//对应ProductDetail类
DynamicGecco.html
.gecco("http://item.jd.com/{code}.html", "consolePipeline")
.stringField("code").requestParameter.build
.stringField("title").csspath("#name > h1").text.build
.stringField("detail").csspath("#product-detail-2").build
.stringField("image").csspath("#spec-n1 img").image("d:/gecco/jd/img").build
.field("price", FieldType.type(JDPrice.class)).ajax("http://p.3.cn/prices/get%3Ftyp ... %3DJ_{code}").build
.field("jdAd", FieldType.type(JDad.class)).ajax("http://cd.jd.com/promotion/v2?skuId={code}&area=1_2805_2855_0&cat=737%2C794%2C798").build
.register;
HttpGetRequest start = new HttpGetRequest("http://www.jd.com/allSort.aspx");
start.setCharset("GBK");
GeccoEngine.create
.classpath("com.geccocrawler.gecco.demo.jd")
.start(start)
.interval(2000)
.run;
}
规则定义好后,就可以启动GeccoEngine了,和之前一样。可以看出,前面的例子定义了7个bean,但是这里只需要一个类。
语法解释 JsonPipeline
Pipeline 的写法也和以前不一样。因为是运行时生成的bean,所以定义的bean不能像以前那样直接使用。Gecco 会将所有 bean 转换为 JSONObject,并通过 json 操作获取捕获的信息。下面是DynamicJD定义的两条Pipeline:
@PipelineName("allSortJsonPipeline")
public class AllSortJsonPipeline extends JsonPipeline {
public static List sortRequests = new ArrayList;
@Override
public void process(JSONObject allSort) {
HttpRequest currRequest = HttpGetRequest.fromJson(allSort.getJSONObject("request"));
JSONArray categorys = allSort.getJSONArray("mobile");
process(currRequest, categorys);
}
private void process(HttpRequest currRequest, JSONArray categorys) {
if(categorys == null) {
return;
}
for(int i = 0; i < categorys.size; i++) {
JSONObject category = categorys.getJSONObject(i);
JSONArray hrefs = category.getJSONArray("categorys");
for(int j = 0; j < hrefs.size; j++) {
String url = hrefs.getJSONObject(j).getString("url")+"&delivery=1&page=1&JL=4_10_0&go=0";
SchedulerContext.into(currRequest.subRequest(url));
}
}
}
}
产品列表处理Pipeline,对应原ProductListPipeline
@PipelineName("productListPipeline")
public class ProductListPipeline implements Pipeline {
@Override
public void process(ProductList productList) {
HttpRequest currRequest = productList.getRequest;
//下一页继续抓取
int currPage = productList.getCurrPage;
int nextPage = currPage + 1;
int totalPage = productList.getTotalPage;
if(nextPage newRule = DynamicGecco
.html(rule1.getName)
.gecco("https://github.com/xtuhcy/gecco", "consolePipeline")
.intField("fork").csspath(".pagehead-actions li:nth-child(3) .social-count").text.build
.removeField("star")
.loadClass;
//注册新规则
ge.register(newRule);
} catch(Exception ex) {
ex.printStackTrace;
} finally {
//规则更新完毕
ge.endUpdateRule;
}
线下有规矩
已经定义好的规则,我们可以下线如下:
try {
//开始更新规则
ge.beginUpdateRule;
//下线之前的规则
ge.unregister(rule);
} catch(Exception ex) {
ex.printStackTrace;
} finally {
//规则更新完毕
ge.endUpdateRule;
}
至此,爬虫规则的添加/修改/删除已经实现。您可以愉快地配置爬虫规则!
完整的demo代码可以参考github上的源码,位于com.geccocrawler.gecco.demo.dynamic包中。
java爬虫抓取动态网页(爬虫小白给了个任务要抓一些数据,觉着没什么问题)
网站优化 • 优采云 发表了文章 • 0 个评论 • 96 次浏览 • 2022-02-05 14:02
爬虫小白,昨天领导给了一个任务,抓一些数据。看完下一页,我以为是简单的页面分析。我觉得没有问题。
页:
要求:高校、专业查询的数据按原样采集
1、问题
最初采用requests+BeautifulSoup分析的方式,抓取高校查询的数据没有问题(代码在最后),但是抓取专业查询的数据时,出现了不一致抓到的页面和浏览器看到的,每次爬取的都是高校查询的数据,修改参数也没用。应该是js的问题(懂的可以告诉我)。
查了半天,问题还是没有解决。我只能叫大佬(大佬厉害)。大佬推荐使用pyppeteer。
2、pyppeteer 安装
在 Anaconda Prompt 中执行
pip install pyppeteer -i https://pypi.tuna.tsinghua.edu.cn/simple
安装时出错:
Cannot uninstall ‘certifi‘. It is a distutils installed project and thus we cannot accurately determ
解决方案:
Chromium 会在第一次执行 pyppeteer 程序时自动下载。如果网络不允许,可以离线下载安装
2、解决问题
所有设备都安装好了,你可以在这里阅读并开始解决问题。仿真过程如下:
① 进入页面;
② 点击专业查询;
③ 点击查询;
④ 分析数据; 查看全部
java爬虫抓取动态网页(爬虫小白给了个任务要抓一些数据,觉着没什么问题)
爬虫小白,昨天领导给了一个任务,抓一些数据。看完下一页,我以为是简单的页面分析。我觉得没有问题。
页:
要求:高校、专业查询的数据按原样采集
1、问题
最初采用requests+BeautifulSoup分析的方式,抓取高校查询的数据没有问题(代码在最后),但是抓取专业查询的数据时,出现了不一致抓到的页面和浏览器看到的,每次爬取的都是高校查询的数据,修改参数也没用。应该是js的问题(懂的可以告诉我)。
查了半天,问题还是没有解决。我只能叫大佬(大佬厉害)。大佬推荐使用pyppeteer。
2、pyppeteer 安装
在 Anaconda Prompt 中执行
pip install pyppeteer -i https://pypi.tuna.tsinghua.edu.cn/simple
安装时出错:
Cannot uninstall ‘certifi‘. It is a distutils installed project and thus we cannot accurately determ
解决方案:
Chromium 会在第一次执行 pyppeteer 程序时自动下载。如果网络不允许,可以离线下载安装
2、解决问题
所有设备都安装好了,你可以在这里阅读并开始解决问题。仿真过程如下:
① 进入页面;
② 点击专业查询;
③ 点击查询;
④ 分析数据;
java爬虫抓取动态网页(动态web的网络爬虫的历史及现状(组图)!)
网站优化 • 优采云 发表了文章 • 0 个评论 • 54 次浏览 • 2022-02-04 14:07
动态网页的网络爬虫研究 1 网络爬虫的历史与现状 网络爬虫是一种自动提取网页的程序。如果将互联网比作蜘蛛网,那么爬虫就是在网络上四处爬行的蜘蛛。传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在对网页进行爬取的过程中,不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。如果把整个互联网看成一个网站,那么网络蜘蛛就可以利用这个原理爬取互联网上的所有网页。随着互联网从Web1.0时代到Web2.0时代的快速发展,由于Ajax异步加载的特点,为了减轻服务器压力,基于Ajax的动态加载技术解决方案已成为大公司的首选。但随着移动互联网的兴起,JavaScript在移动端和PC端的优良特性得到广泛发挥,基于前端MVC/MVVM的模型逐渐进入各大互联网公司的首选方案。数据显示,2011年互联网上动态网页与静态网页的比例为12.1:1。2014年,动态网页与静态网页的比例攀升至22:1。动态网页的急剧崛起,让各大搜索引擎公司觉得基于动态网页的网络爬虫将变得越来越重要。2 问题现状及解决方案2.
传统爬虫根据url对页面进行爬取,解析页面内容提取新的url用于下一次爬取机制,难以完成。其次,现在网上有很多对实时性要求很高的网站,比如股票、优采云票等等,这些网站里面收录了很多数据并随着服务器不断更新。搜索引擎在抓取这些数据时,由于数据需要下载到本地,所以一直存在数据同步的问题,但是这些实时数据的商业价值非常大。因此,简单来说,当前搜索引擎爬虫系统遇到动态网页时的主要问题是:(1)无法提取Ajax加载的动态页面中的url。(2) 基于 HTTP 请求-响应模型。用户在浏览器中输入一个网页的url,客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回该页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。基于 HTTP 请求-响应模型。用户在浏览器中输入一个网页的url,客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回该页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@>文本对象模型(DOM)。DOM用于访问和处理HTML和XML文档。它可以构造HTML和XML文档。(4)正则表达式。根据正则的优良特性of 表达式可以根据条件快速提取 HTML 文本中的指定元素。所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@>文本对象模型(DOM)。DOM用于访问和处理HTML和XML文档。它可以构造HTML和XML文档。(4)正则表达式。根据正则的优良特性of 表达式可以根据条件快速提取 HTML 文本中的指定元素。
2.3 解决方案 AJAX 使用 JavaScript 驱动的异步请求/响应机制。而且,在 Ajax 应用中,JavaScript 会对 DOM 结构进行大量的更改,甚至页面的所有内容都是通过 JavaScript 直接从服务器读取和动态绘制的。因此,爬虫引擎不能仅仅由基于HTTP的协议驱动,而必须由事件驱动。对于实时数据,系统的实时特性主要体现在两个方面:数据更新的实时性;数据变化后其他服务的实时性。面对海量数据,由于捕捉能力有限,无法快速更新所有数据信息。为了保证用户对实时数据的高要求,热门数据的数据更新应尽可能优先,因此实时捕获数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。所以实时捕捉数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。所以实时捕捉数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。
这种实时爬取策略称为“查询驱动爬取”(QTC,Query Triggered Crawling)。价格服务器除了实时捕捉和管理所有商品的价格外,还需要向其他服务提供价格变化的更新事件(如降价提醒、全网比价等)。如何让其他服务获得实时的商品价格变化信息?我们首先介绍观察者模式。观察者模式(也称为发布/订阅模式)是一种软件设计模式。在这种模式中,目标对象管理依赖它的所有观察者对象,并在其自身状态发生变化时主动发送通知。这通常通过调用每个观察者提供的方法来完成。这种模式通常用于实现事件处理系统。观察者模式在数据变化的实时通知中得到了广泛的应用,使得服务具有高集群、低耦合的特点。根据不同的应用,爬虫系统在很多方面都有所不同。一般来说,爬虫可以分为以下三种: 批量爬虫:批量爬虫具有比较明确的抓取范围和目标。当达到这个设定目标时,爬行过程停止。至于具体的目标,可能会有所不同,可能设置一定数量的要爬取的网页就够了,也可能是设置爬取所消耗的时间。增量爬虫:与批量爬虫不同,增量爬虫会保持连续爬取。对于被抓取的网页,它们应该定期更新,因为互联网的网页在不断变化,新的网页不断增加。网页被删除或网页内容发生变化是常有的事,增量爬虫需要及时反映这种变化,所以在持续的爬取过程中,要么是爬取新的网页,要么是更新已有的网页.
常见的商业搜索引擎爬虫基本属于这一类。垂直爬虫(Focused Crawter):垂直爬虫专注于特定主题内容IC或属于特定行业的网页。例如,对于在线旅游,您只需要从互联网页面中找到与在线旅游相关的页面内容。不考虑其他行业内容。垂直爬虫最大的特点和难点之一是如何识别网页内容是否属于指定行业或主题。从节省系统资源的角度来看,不可能把所有的网页都下载下来再过滤。这种资源浪费太多了。爬虫往往需要在爬取阶段动态识别某个URL是否与主题相关。并且尽量不要去抓取不相关的页面,以达到节省资源的目的。垂直搜索网站或垂直行业网站往往需要这种爬虫。3 结束语对于使用JavaScript进行动态页面的爬取,主要的技术方案有:(1)基于事件驱动的爬虫机制。(2)使用观察者模式和查询驱动的爬取方式捕获Get实时数据,并介绍目前流行的爬虫爬取方案。使用观察者模式和查询驱动的爬取方式获取实时数据。并介绍目前流行的爬虫爬取方案。使用观察者模式和查询驱动的爬取方式获取实时数据。并介绍目前流行的爬虫爬取方案。 查看全部
java爬虫抓取动态网页(动态web的网络爬虫的历史及现状(组图)!)
动态网页的网络爬虫研究 1 网络爬虫的历史与现状 网络爬虫是一种自动提取网页的程序。如果将互联网比作蜘蛛网,那么爬虫就是在网络上四处爬行的蜘蛛。传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在对网页进行爬取的过程中,不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。如果把整个互联网看成一个网站,那么网络蜘蛛就可以利用这个原理爬取互联网上的所有网页。随着互联网从Web1.0时代到Web2.0时代的快速发展,由于Ajax异步加载的特点,为了减轻服务器压力,基于Ajax的动态加载技术解决方案已成为大公司的首选。但随着移动互联网的兴起,JavaScript在移动端和PC端的优良特性得到广泛发挥,基于前端MVC/MVVM的模型逐渐进入各大互联网公司的首选方案。数据显示,2011年互联网上动态网页与静态网页的比例为12.1:1。2014年,动态网页与静态网页的比例攀升至22:1。动态网页的急剧崛起,让各大搜索引擎公司觉得基于动态网页的网络爬虫将变得越来越重要。2 问题现状及解决方案2.
传统爬虫根据url对页面进行爬取,解析页面内容提取新的url用于下一次爬取机制,难以完成。其次,现在网上有很多对实时性要求很高的网站,比如股票、优采云票等等,这些网站里面收录了很多数据并随着服务器不断更新。搜索引擎在抓取这些数据时,由于数据需要下载到本地,所以一直存在数据同步的问题,但是这些实时数据的商业价值非常大。因此,简单来说,当前搜索引擎爬虫系统遇到动态网页时的主要问题是:(1)无法提取Ajax加载的动态页面中的url。(2) 基于 HTTP 请求-响应模型。用户在浏览器中输入一个网页的url,客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回该页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。基于 HTTP 请求-响应模型。用户在浏览器中输入一个网页的url,客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回该页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@>文本对象模型(DOM)。DOM用于访问和处理HTML和XML文档。它可以构造HTML和XML文档。(4)正则表达式。根据正则的优良特性of 表达式可以根据条件快速提取 HTML 文本中的指定元素。所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@>文本对象模型(DOM)。DOM用于访问和处理HTML和XML文档。它可以构造HTML和XML文档。(4)正则表达式。根据正则的优良特性of 表达式可以根据条件快速提取 HTML 文本中的指定元素。
2.3 解决方案 AJAX 使用 JavaScript 驱动的异步请求/响应机制。而且,在 Ajax 应用中,JavaScript 会对 DOM 结构进行大量的更改,甚至页面的所有内容都是通过 JavaScript 直接从服务器读取和动态绘制的。因此,爬虫引擎不能仅仅由基于HTTP的协议驱动,而必须由事件驱动。对于实时数据,系统的实时特性主要体现在两个方面:数据更新的实时性;数据变化后其他服务的实时性。面对海量数据,由于捕捉能力有限,无法快速更新所有数据信息。为了保证用户对实时数据的高要求,热门数据的数据更新应尽可能优先,因此实时捕获数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。所以实时捕捉数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。所以实时捕捉数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。
这种实时爬取策略称为“查询驱动爬取”(QTC,Query Triggered Crawling)。价格服务器除了实时捕捉和管理所有商品的价格外,还需要向其他服务提供价格变化的更新事件(如降价提醒、全网比价等)。如何让其他服务获得实时的商品价格变化信息?我们首先介绍观察者模式。观察者模式(也称为发布/订阅模式)是一种软件设计模式。在这种模式中,目标对象管理依赖它的所有观察者对象,并在其自身状态发生变化时主动发送通知。这通常通过调用每个观察者提供的方法来完成。这种模式通常用于实现事件处理系统。观察者模式在数据变化的实时通知中得到了广泛的应用,使得服务具有高集群、低耦合的特点。根据不同的应用,爬虫系统在很多方面都有所不同。一般来说,爬虫可以分为以下三种: 批量爬虫:批量爬虫具有比较明确的抓取范围和目标。当达到这个设定目标时,爬行过程停止。至于具体的目标,可能会有所不同,可能设置一定数量的要爬取的网页就够了,也可能是设置爬取所消耗的时间。增量爬虫:与批量爬虫不同,增量爬虫会保持连续爬取。对于被抓取的网页,它们应该定期更新,因为互联网的网页在不断变化,新的网页不断增加。网页被删除或网页内容发生变化是常有的事,增量爬虫需要及时反映这种变化,所以在持续的爬取过程中,要么是爬取新的网页,要么是更新已有的网页.
常见的商业搜索引擎爬虫基本属于这一类。垂直爬虫(Focused Crawter):垂直爬虫专注于特定主题内容IC或属于特定行业的网页。例如,对于在线旅游,您只需要从互联网页面中找到与在线旅游相关的页面内容。不考虑其他行业内容。垂直爬虫最大的特点和难点之一是如何识别网页内容是否属于指定行业或主题。从节省系统资源的角度来看,不可能把所有的网页都下载下来再过滤。这种资源浪费太多了。爬虫往往需要在爬取阶段动态识别某个URL是否与主题相关。并且尽量不要去抓取不相关的页面,以达到节省资源的目的。垂直搜索网站或垂直行业网站往往需要这种爬虫。3 结束语对于使用JavaScript进行动态页面的爬取,主要的技术方案有:(1)基于事件驱动的爬虫机制。(2)使用观察者模式和查询驱动的爬取方式捕获Get实时数据,并介绍目前流行的爬虫爬取方案。使用观察者模式和查询驱动的爬取方式获取实时数据。并介绍目前流行的爬虫爬取方案。使用观察者模式和查询驱动的爬取方式获取实时数据。并介绍目前流行的爬虫爬取方案。
java爬虫抓取动态网页(一个通用的网络爬虫的基本结构及工作流程(组图))
网站优化 • 优采云 发表了文章 • 0 个评论 • 72 次浏览 • 2022-02-02 20:10
1、MOOC的爬虫教程
2、%2Fbook%2F1709
网络爬虫是搜索引擎爬虫系统的重要组成部分。爬虫的主要目的是将互联网上的网页下载到本地,形成网络内容的镜像备份。本篇博客主要对爬虫和爬虫系统进行简要概述。
一、网络爬虫的基本结构和工作流程
一个通用网络爬虫的框架如图所示:
网络爬虫的基本工作流程如下:
1.首先选择一个精心挑选的种子 URL 的子集;
2.将这些网址放入待抓取的网址队列中;
3. 从待爬取的URL队列中取出待爬取的URL,解析DNS,得到主机的IP,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URL 队列。
4.解析URL队列中已经爬取的URL,分析其中的其他URL,将URL放入待爬取的URL队列,从而进入下一个循环。
二、从爬虫的角度划分互联网
相应地,互联网上的所有页面可以分为五个部分:
1.下载了未过期的网页
2.已下载和过期网页:抓取的网页实际上是互联网内容的镜像和备份。互联网是动态变化的,互联网上的一些内容也发生了变化。您访问的页面已过期。
3.待下载网页:URL队列中待抓取的页面
4. 已知网页:尚未被爬取,也不在待爬取的URL队列中,但分析已爬取的页面得到的URL或待爬取URL对应的页面可以被认为是一个已知的网页。
5.还有一些网页是爬虫无法直接爬取下载的。称为不可知网页。
三、抓取策略
在爬虫系统中,待爬取的 URL 队列是一个重要的部分。待爬取的URL队列中的URL的排列顺序也是一个重要的问题,因为它涉及到先爬到哪个页面,再爬到哪个页面。确定这些 URL 排列顺序的方法称为爬取策略。下面重点介绍几种常见的爬取策略:
1.深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,每次一个链接跟踪每个链接,处理完该行后移动到下一个起始页,并继续跟踪该链接。我们以下图为例:
遍历的路径:AFG EHI BCD
2.广度优先遍历策略
广度优先遍历的基本思想是将新下载的网页中找到的链接直接插入待爬取URL队列的末尾。也就是说,网络爬虫会先爬取起始网页链接的所有网页,然后选择其中一个链接的网页,继续爬取该网页链接的所有网页。或者以上图为例:
遍历路径:ABCDEF GHI
3.反向链接计数策略
反向链接数是指从其他网页指向一个网页的链接数。反向链接的数量表示网页内容被他人推荐的程度。因此,在很多情况下,搜索引擎的爬取系统会使用这个指标来评估网页的重要性,从而确定不同网页的爬取顺序。
在真实的网络环境中,由于广告链接和作弊链接的存在,反向链接的数量并不能完全等同于他人的重要性。因此,搜索引擎倾向于考虑一些可靠的反向链接计数。
4.部分PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于下载的网页,与待爬取的URL队列中的URL一起形成一组网页,计算每个页面的PageRank值. URL 按 PageRank 值排序,并按该顺序抓取页面。
如果每次爬取一个页面都重新计算一次PageRank值,一个折中的方案是每次爬取K个页面都重新计算一次PageRank值。但是这种情况还是有一个问题:对于下载页面中分析的链接,也就是我们前面提到的那部分未知网页,暂时没有PageRank值。为了解决这个问题,给这些页面一个临时的PageRank值:把这个网页的所有传入链接传入的PageRank值聚合起来,从而形成未知页面的PageRank值,从而参与排序. 以下示例说明:
5.OPIC 政策政策
该算法实际上为页面分配了一个重要性分数。在算法开始之前,所有页面都会获得相同的初始现金。当某个页面P被下载时,P的现金分配给从P分析的所有链接,P的现金被清空。根据现金数量对待爬取URL队列中的所有页面进行排序。
6.大网站优先策略
所有待爬取的URL队列中的网页都按照它们所属的网站进行分类。网站需要下载的页面较多,请先下载。这种策略也称为大站点优先策略。 查看全部
java爬虫抓取动态网页(一个通用的网络爬虫的基本结构及工作流程(组图))
1、MOOC的爬虫教程
2、%2Fbook%2F1709
网络爬虫是搜索引擎爬虫系统的重要组成部分。爬虫的主要目的是将互联网上的网页下载到本地,形成网络内容的镜像备份。本篇博客主要对爬虫和爬虫系统进行简要概述。
一、网络爬虫的基本结构和工作流程
一个通用网络爬虫的框架如图所示:

网络爬虫的基本工作流程如下:
1.首先选择一个精心挑选的种子 URL 的子集;
2.将这些网址放入待抓取的网址队列中;
3. 从待爬取的URL队列中取出待爬取的URL,解析DNS,得到主机的IP,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URL 队列。
4.解析URL队列中已经爬取的URL,分析其中的其他URL,将URL放入待爬取的URL队列,从而进入下一个循环。
二、从爬虫的角度划分互联网
相应地,互联网上的所有页面可以分为五个部分:

1.下载了未过期的网页
2.已下载和过期网页:抓取的网页实际上是互联网内容的镜像和备份。互联网是动态变化的,互联网上的一些内容也发生了变化。您访问的页面已过期。
3.待下载网页:URL队列中待抓取的页面
4. 已知网页:尚未被爬取,也不在待爬取的URL队列中,但分析已爬取的页面得到的URL或待爬取URL对应的页面可以被认为是一个已知的网页。
5.还有一些网页是爬虫无法直接爬取下载的。称为不可知网页。
三、抓取策略
在爬虫系统中,待爬取的 URL 队列是一个重要的部分。待爬取的URL队列中的URL的排列顺序也是一个重要的问题,因为它涉及到先爬到哪个页面,再爬到哪个页面。确定这些 URL 排列顺序的方法称为爬取策略。下面重点介绍几种常见的爬取策略:
1.深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,每次一个链接跟踪每个链接,处理完该行后移动到下一个起始页,并继续跟踪该链接。我们以下图为例:

遍历的路径:AFG EHI BCD
2.广度优先遍历策略
广度优先遍历的基本思想是将新下载的网页中找到的链接直接插入待爬取URL队列的末尾。也就是说,网络爬虫会先爬取起始网页链接的所有网页,然后选择其中一个链接的网页,继续爬取该网页链接的所有网页。或者以上图为例:
遍历路径:ABCDEF GHI
3.反向链接计数策略
反向链接数是指从其他网页指向一个网页的链接数。反向链接的数量表示网页内容被他人推荐的程度。因此,在很多情况下,搜索引擎的爬取系统会使用这个指标来评估网页的重要性,从而确定不同网页的爬取顺序。
在真实的网络环境中,由于广告链接和作弊链接的存在,反向链接的数量并不能完全等同于他人的重要性。因此,搜索引擎倾向于考虑一些可靠的反向链接计数。
4.部分PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于下载的网页,与待爬取的URL队列中的URL一起形成一组网页,计算每个页面的PageRank值. URL 按 PageRank 值排序,并按该顺序抓取页面。
如果每次爬取一个页面都重新计算一次PageRank值,一个折中的方案是每次爬取K个页面都重新计算一次PageRank值。但是这种情况还是有一个问题:对于下载页面中分析的链接,也就是我们前面提到的那部分未知网页,暂时没有PageRank值。为了解决这个问题,给这些页面一个临时的PageRank值:把这个网页的所有传入链接传入的PageRank值聚合起来,从而形成未知页面的PageRank值,从而参与排序. 以下示例说明:
5.OPIC 政策政策
该算法实际上为页面分配了一个重要性分数。在算法开始之前,所有页面都会获得相同的初始现金。当某个页面P被下载时,P的现金分配给从P分析的所有链接,P的现金被清空。根据现金数量对待爬取URL队列中的所有页面进行排序。
6.大网站优先策略
所有待爬取的URL队列中的网页都按照它们所属的网站进行分类。网站需要下载的页面较多,请先下载。这种策略也称为大站点优先策略。
java爬虫抓取动态网页(即为如何通过selenium-java爬取异步加载的数据的方法)
网站优化 • 优采云 发表了文章 • 0 个评论 • 59 次浏览 • 2022-02-02 20:10
在之前的系列文章中介绍了如何使用httpclient抓取页面html以及如何使用jsoup分析html源文件的内容得到我们想要的数据,但是有时候这两种方法都不能使用捕获我们想要的数据。所需数据,例如,请参见以下示例。
1.需求场景:
如果要抢到股票的最新价格,F12页信息如下:
按照前面的方法,爬取的代码如下:
/**
* @description: 爬取股票的最新股价
* @author: JAVA开发老菜鸟
* @date: 2021-10-16 21:47
*/
public class StockPriceSpider {
Logger logger = LoggerFactory.getLogger(this.getClass());
public static void main(String[] args) {
StockPriceSpider stockPriceSpider = new StockPriceSpider();
String html = stockPriceSpider.httpClientProcess();
stockPriceSpider.jsoupProcess(html);
}
private String httpClientProcess() {
String html = "";
String uri = "http://quote.eastmoney.com/sh600036.html";
//1.生成httpclient,相当于该打开一个浏览器
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
//2.创建get请求,相当于在浏览器地址栏输入 网址
HttpGet request = new HttpGet(uri);
try {
request.setHeader("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36");
request.setHeader("accept", "application/json, text/javascript, */*; q=0.01");
// HttpHost proxy = new HttpHost("3.211.17.212", 80);
// RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
// request.setConfig(config);
//3.执行get请求,相当于在输入地址栏后敲回车键
response = httpClient.execute(request);
//4.判断响应状态为200,进行处理
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//5.获取响应内容
HttpEntity httpEntity = response.getEntity();
html = EntityUtils.toString(httpEntity, "utf-8");
logger.info("访问{} 成功,返回页面数据{}", uri, html);
} else {
//如果返回状态不是200,比如404(页面不存在)等,根据情况做处理,这里略
logger.info("访问{},返回状态不是200", uri);
logger.info(EntityUtils.toString(response.getEntity(), "utf-8"));
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//6.关闭
HttpClientUtils.closeQuietly(response);
HttpClientUtils.closeQuietly(httpClient);
}
return html;
}
private void jsoupProcess(String html) {
Document document = Jsoup.parse(html);
Element price = document.getElementById("price9");
logger.info("股价为:>>> {}", price.text());
}
}
运行结果:
纳尼,股价是“-”?不可能的。
无法爬取正确结果的原因是因为这个值是在网站上异步加载渲染的,所以无法正常获取。
2.爬取异步加载数据的java方法
如何爬取异步加载的数据?通常有两种方法:
2.1 内置浏览器内核
内置浏览器就是在爬虫程序中启动一个浏览器内核,让js渲染出来的页面和静态页面一样。常用的内核有
这里我选择了 Selenium,它是一个模拟浏览器和自动化测试工具。它提供了一组 API 来与真正的浏览器内核交互。当然,爬虫也可以使用它。
具体方法如下:
2.2 逆向分析
反向解析的方法是通过F12找到Ajax异步数据获取的链接,直接调用链接得到json结果,然后直接解析json结果得到想要的数据。
此方法的关键是找到 Ajax 链接。这个方法我没研究过,有兴趣可以百度下载。稍微在这里。
3.结束语
以上就是如何通过selenium-java爬取异步加载的数据。通过这个方法,我写了一个小工具:
仓位市值通知系统,他每天会根据自己的仓位配置自动计算账户总市值,并发送邮件通知到指定邮箱。
使用的技术如下:
相关代码已经上传到我的码云,有兴趣的可以看看。 查看全部
java爬虫抓取动态网页(即为如何通过selenium-java爬取异步加载的数据的方法)
在之前的系列文章中介绍了如何使用httpclient抓取页面html以及如何使用jsoup分析html源文件的内容得到我们想要的数据,但是有时候这两种方法都不能使用捕获我们想要的数据。所需数据,例如,请参见以下示例。
1.需求场景:
如果要抢到股票的最新价格,F12页信息如下:

按照前面的方法,爬取的代码如下:
/**
* @description: 爬取股票的最新股价
* @author: JAVA开发老菜鸟
* @date: 2021-10-16 21:47
*/
public class StockPriceSpider {
Logger logger = LoggerFactory.getLogger(this.getClass());
public static void main(String[] args) {
StockPriceSpider stockPriceSpider = new StockPriceSpider();
String html = stockPriceSpider.httpClientProcess();
stockPriceSpider.jsoupProcess(html);
}
private String httpClientProcess() {
String html = "";
String uri = "http://quote.eastmoney.com/sh600036.html";
//1.生成httpclient,相当于该打开一个浏览器
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
//2.创建get请求,相当于在浏览器地址栏输入 网址
HttpGet request = new HttpGet(uri);
try {
request.setHeader("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36");
request.setHeader("accept", "application/json, text/javascript, */*; q=0.01");
// HttpHost proxy = new HttpHost("3.211.17.212", 80);
// RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
// request.setConfig(config);
//3.执行get请求,相当于在输入地址栏后敲回车键
response = httpClient.execute(request);
//4.判断响应状态为200,进行处理
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//5.获取响应内容
HttpEntity httpEntity = response.getEntity();
html = EntityUtils.toString(httpEntity, "utf-8");
logger.info("访问{} 成功,返回页面数据{}", uri, html);
} else {
//如果返回状态不是200,比如404(页面不存在)等,根据情况做处理,这里略
logger.info("访问{},返回状态不是200", uri);
logger.info(EntityUtils.toString(response.getEntity(), "utf-8"));
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//6.关闭
HttpClientUtils.closeQuietly(response);
HttpClientUtils.closeQuietly(httpClient);
}
return html;
}
private void jsoupProcess(String html) {
Document document = Jsoup.parse(html);
Element price = document.getElementById("price9");
logger.info("股价为:>>> {}", price.text());
}
}
运行结果:

纳尼,股价是“-”?不可能的。
无法爬取正确结果的原因是因为这个值是在网站上异步加载渲染的,所以无法正常获取。
2.爬取异步加载数据的java方法
如何爬取异步加载的数据?通常有两种方法:
2.1 内置浏览器内核
内置浏览器就是在爬虫程序中启动一个浏览器内核,让js渲染出来的页面和静态页面一样。常用的内核有
这里我选择了 Selenium,它是一个模拟浏览器和自动化测试工具。它提供了一组 API 来与真正的浏览器内核交互。当然,爬虫也可以使用它。
具体方法如下:
2.2 逆向分析
反向解析的方法是通过F12找到Ajax异步数据获取的链接,直接调用链接得到json结果,然后直接解析json结果得到想要的数据。
此方法的关键是找到 Ajax 链接。这个方法我没研究过,有兴趣可以百度下载。稍微在这里。
3.结束语
以上就是如何通过selenium-java爬取异步加载的数据。通过这个方法,我写了一个小工具:
仓位市值通知系统,他每天会根据自己的仓位配置自动计算账户总市值,并发送邮件通知到指定邮箱。
使用的技术如下:
相关代码已经上传到我的码云,有兴趣的可以看看。
java爬虫抓取动态网页(Web网络爬虫系统的功能及应用)
网站优化 • 优采云 发表了文章 • 0 个评论 • 48 次浏览 • 2022-02-02 05:01
1、爬虫技术概述
网络爬虫是根据一定的规则自动从万维网上爬取信息的程序或脚本。广泛应用于互联网搜索引擎或其他类似的网站,它可以自动采集它可以访问的页面的所有内容来获取或更新这些网站@的内容和检索方式>。从功能上来说,爬虫一般分为数据采集、处理、存储三部分。
传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在抓取网页的过程中,它不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。焦点爬虫的工作流程比较复杂。它需要按照一定的网页分析算法过滤掉与主题无关的链接,保留有用的链接,并放入等待抓取的URL队列中。然后,它会根据一定的搜索策略从队列中选择下一个要爬取的网页URL,并重复上述过程,直到达到系统的一定条件并停止。另外,爬虫爬取的所有网页都会被系统存储,进行一定的分析、过滤、索引,以供后续查询和检索;对于重点爬虫来说,这个过程中得到的分析结果也可能对后续的爬取过程给出反馈和指导。
与通用网络爬虫相比,聚焦爬虫还需要解决三个主要问题:
(1) 获取目标的描述或定义;
(2) 网页或数据的分析和过滤;
(3) URL 的搜索策略。
2、爬虫原理
2.1 网络爬虫原理
网络爬虫系统的功能是下载网页数据,为搜索引擎系统提供数据源。许多大型网络搜索引擎系统被称为基于Web数据的搜索引擎系统采集,如Google、百度等。这显示了网络爬虫系统在搜索引擎中的重要性。除了供用户阅读的文字信息外,网页还收录一些超链接信息。网络爬虫系统通过网页中的超链接信息不断获取网络上的其他网页。正是因为这个采集进程像爬虫或者蜘蛛一样在网络上漫游,所以才叫做网络爬虫系统或者网络蜘蛛系统,英文叫Spider或者Crawler。
2.2 网络爬虫系统的工作原理
在网络爬虫的系统框架中,主要流程由控制器、解析器和资源库三部分组成。控制器的主要工作是为多个线程中的每个爬虫线程分配工作任务。解析器的主要工作是下载网页和处理页面,主要是处理一些JS脚本标签、CSS代码内容、空格字符、HTML标签等。爬虫的基本工作是由解析器完成的。资源库用于存储下载的网络资源。通常使用大型数据库,例如 Oracle 数据库来存储和索引它。
控制器
控制器是网络爬虫的第一个控制器。主要负责根据系统发送的URL链接分配线程,然后启动线程调用爬虫爬取网页。
解析器
解析器负责网络爬虫的主要部分。它的主要任务是:下载网页的功能,处理网页的文本,如过滤,提取特殊的HTML标签,分析数据。
资源库
它主要是一个容器,用于存储从网页下载的数据记录,并为索引生成提供目标源。大中型数据库产品包括:Oracle、Sql Server等。
网络爬虫系统一般会选择一些比较重要的出度(网页中超链接数)网站较大的URL作为种子URL集。网络爬虫系统使用这些种子集作为初始 URL 来开始数据爬取。因为网页中收录链接信息,所以会通过已有网页的URL获取一些新的URL。网页之间的指向结构可以看作是一片森林。每个种子 URL 对应的网页是森林中一棵树的根节点。. 这样,网络爬虫系统就可以按照广度优先算法或深度优先算法遍历所有网页。由于深度优先搜索算法可能导致爬虫系统陷入网站内部,不利于搜索距离网站首页比较近的网页信息,一般采用广度优先搜索算法采集网页。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。
网络爬虫的基本工作流程如下:
1.首先选择一个精心挑选的种子 URL 的子集;
2.将这些网址放入待抓取的网址队列中;
3. 从待爬取URL队列中取出待爬取的URL,解析DNS,获取主机IP,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URLs 队列;
4.分析已经爬取的URL队列中的URL,分析其中的其他URL,将这些URL放入待爬取的URL队列,从而进入下一个循环。
2.3 爬取策略
在爬虫系统中,待爬取的 URL 队列是一个重要的部分。待爬取的URL队列中的URL的排列顺序也是一个重要的问题,因为它涉及到先爬到哪个页面,再爬到哪个页面。确定这些 URL 排列顺序的方法称为爬取策略。下面重点介绍几种常见的爬取策略:
2.3.1 深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,每次一个链接跟踪每个链接,处理完该行后移动到下一个起始页,并继续跟踪该链接。我们以下图为例:
遍历的路径:AFG EHI BCD
2.3.2 广度优先遍历策略
广度优先遍历策略的基本思想是将新下载的网页中找到的链接直接放到待爬取的URL队列的末尾。也就是说,网络爬虫会先爬取起始网页链接的所有网页,然后选择其中一个链接的网页,继续爬取该网页链接的所有网页。或者以上图为例:
遍历路径:ABCDEF GHI
2.3.3 反向链接策略
反向链接数是指从其他网页指向一个网页的链接数。反向链接的数量表示网页内容被他人推荐的程度。因此,在很多情况下,搜索引擎的爬取系统会使用这个指标来评估网页的重要性,从而确定不同网页的爬取顺序。
在真实的网络环境中,由于广告链接和作弊链接的存在,反向链接的数量并不能完全等同于他人的重要性。因此,搜索引擎倾向于考虑一些可靠的反向链接计数。
2.3.4 部分PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于下载的网页,与待爬取的URL队列中的URL一起,形成一组网页,计算每个页面的PageRank值. URL 按 PageRank 值排序,并按该顺序抓取页面。
如果每次爬取一个页面都重新计算一次PageRank值,折中的解决方案是:每爬完K个页面,重新计算一次PageRank值。但是这种情况还是有一个问题:对于下载页面中分析的链接,也就是我们前面提到的未知网页部分,暂时没有PageRank值。为了解决这个问题,会给这些页面一个临时的PageRank值:将这个网页所有传入链接传入的PageRank值聚合起来,从而形成未知页面的PageRank值,从而参与排序。
2.3.5 OPIC 政策方针
该算法实际上为页面分配了一个重要性分数。在算法开始之前,所有页面都会获得相同的初始现金。当某个页面P被下载时,P的现金分配给从P分析的所有链接,P的现金被清空。根据现金数量对待爬取URL队列中的所有页面进行排序。
2.3.6 大网站优先策略
所有待爬取的URL队列中的网页都按照它们所属的网站进行分类。网站需要下载的页面较多,请先下载。这种策略也称为大站点优先策略。
3、爬虫分类
我应该选择 Nutch、Crawler4j、WebMagic、scrapy、WebCollector 还是其他来开发网络爬虫?上面提到的爬虫类,基本上可以分为三类:
(1)分布式爬虫:Nutch
(2)JAVA 爬虫:Crawler4j、WebMagic、WebCollector
(3)非JAVA爬虫:scrapy(基于Python语言开发)
3.1 分布式爬虫
爬虫使用分布式,主要解决两个问题:
1)海量网址管理
2)网速
现在比较流行的分布式爬虫是Apache的Nutch。但是对于大多数用户来说,Nutch 是这些爬虫中最差的选择,原因如下:
1)Nutch 是为搜索引擎设计的爬虫。大多数用户需要一个爬虫来进行准确的数据爬取(精细提取)。Nutch 运行的三分之二的流程是为搜索引擎设计的。提取意义不大。换句话说,使用 Nutch 进行数据提取会在不必要的计算上浪费大量时间。而如果你试图通过Nutch的二次开发使其适合提取业务,你基本上会破坏Nutch的框架,将Nutch改得面目全非,并且有能力修改Nutch,还不如自己写一个新的. 分布式爬虫框架。
2)Nutch 依赖hadoop 运行,hadoop 本身消耗大量时间。如果集群机器数量少,爬取速度不如单机爬虫快。
3)虽然Nutch有一套插件机制,但还是作为亮点来宣传的。可以看到一些开源的Nutch插件,提供精准提取功能。但是任何开发过 Nutch 插件的人都知道 Nutch 的插件系统有多糟糕。使用反射机制加载和调用插件,使得程序的编写和调试变得异常困难,更不用说在其上开发复杂的提取系统了。并且 Nutch 没有提供对应的插件挂载点进行精细提取。Nutch的插件只有五六个挂载点,而这五六个挂载点都是给搜索引擎服务的,不提供细提取的挂载点。Nutch 的大部分精炼提取插件都安装在“解析器”安装点上。这个挂载点其实是用来解析链接(为后续爬取提供URL)和提供一些搜索引擎的。易于提取的网页信息(元信息、网页文本)。
4)使用Nutch进行爬虫的二次开发,编写和调试爬虫所需的时间往往是单机爬虫所需时间的十倍以上。学习 Nutch 源码的成本非常高,更何况团队中的每个人都必须了解 Nutch 源码。在调试过程中,会出现程序本身以外的各种问题(hadoop问题、hbase问题)。
5)很多人说Nutch2有gora,可以将数据持久化到avro文件、hbase、mysql等,其实很多人理解错了。这里所说的持久化数据是指在avro、hbase、mysql中存储URL信息(URL管理所需的数据)。不是您要提取的结构化数据。事实上,对于大多数人来说,URL 信息存在于何处并不重要。
6)Nutch2 的版本目前不适合开发。Nutch的官方稳定版是nutch2.2.1,但是这个版本绑定了gora-0.3。如果要使用hbase和nutch(大多数人使用nutch2是为了使用hbase),只能使用版本0.90左右的hbase,相应地,将hadoop版本降低到hadoop 0.左右@>2。而且nutch2的官方教程也颇具误导性。Nutch2的教程有两个,分别是Nutch1.x和Nutch2.x。这个Nutch2.x官网是为了支持hbase0.94而写的。但其实这个Nutch2.x是指Nutch2.3之前和Nutch2.2.1之后的一个版本,在官方SVN中不断更新。而且它'
所以,如果你不是搜索引擎,尽量不要选择 Nutch 作为爬虫。一些团队喜欢跟风。他们坚持选择Nutch来开发精制履带。事实上,这是针对Nutch的声誉。当然,最终的结果往往是项目延期。
如果你在做搜索引擎,Nutch1.x 是一个非常不错的选择。Nutch1.x 和 solr 或 es 可以组成一个非常强大的搜索引擎。如果必须使用 Nutch2,建议等到 Nutch2.3 发布。当前的 Nutch2 是一个非常不稳定的版本。
3.2 JAVA爬虫
在这里,将JAVA爬虫划分为一个单独的类别,因为JAVA在网络爬虫的生态系统中非常完善。相关资料也是最全的。这里可能有争议,我只是随便说说。
其实开源网络爬虫(框架)的开发很简单,难点和复杂的问题已经被前人解决了(比如DOM树解析定位、字符集检测、海量URL去重),可以说没有技术含量。包括Nutch,其实Nutch的技术难点就是开发hadoop,代码本身也很简单。从某种意义上说,网络爬虫类似于遍历本机的文件以查找文件中的信息。没有任何困难。选择开源爬虫框架的原因是为了省事。比如爬虫的URL管理、线程池等模块,任何人都可以做,但是需要一段时间的调试和修改才能稳定下来。
对于爬虫的功能。用户比较关心的问题往往是:
1)爬虫是否支持多线程,爬虫是否可以使用代理,爬虫是否可以爬取重复数据,爬虫是否可以爬取JS生成的信息?
不支持多线程、不支持代理、不能过滤重复URL的不叫开源爬虫,叫循环执行http请求。
js生成的信息能否被爬取与爬虫本身关系不大。爬虫主要负责遍历网站和下载页面。爬取js产生的信息与网页信息提取模块有关,往往需要通过模拟浏览器(htmlunit、selenium)来完成。这些模拟浏览器通常需要花费大量时间来处理一个页面。因此,一种策略是利用这些爬虫遍历网站,当遇到需要解析的页面时,将网页的相关信息提交给模拟浏览器,完成对JS生成信息的提取。
2)爬虫可以抓取ajax信息吗?
网页上有一些异步加载的数据。爬取数据有两种方式:使用模拟浏览器(问题1中描述),或者分析ajax的http请求,自己生成ajax请求的url,获取返回的数据。如果你自己生成ajax请求,那么使用开源爬虫有什么意义呢?其实就是利用开源爬虫的线程池和URL管理功能(比如断点爬取)。
如果我已经可以生成我需要的ajax请求(列表),我该如何使用这些爬虫来爬取这些请求呢?
爬虫往往被设计成广度遍历或深度遍历的方式来遍历静态或动态页面。爬取ajax信息属于深网(deep web)的范畴,虽然大部分爬虫并不直接支持。但它也可以通过某些方式完成。例如,WebCollector 使用广度遍历来遍历 网站。爬虫的第一轮爬取就是爬取种子集(seeds)中的所有url。简单来说就是将生成的ajax请求作为种子,放入爬虫中。使用爬虫对这些种子进行深度为 1 的广度遍历(默认为广度遍历)。
3)爬虫如何爬取待登录的网站?
这些开源爬虫都支持在爬取时指定cookies,而模拟登录主要依赖cookies。至于如何获取cookies,就不是爬虫管理的问题了。您可以手动获取cookies,使用http请求模拟登录,或者使用模拟浏览器自动登录。
4)爬虫如何从网页中提取信息?
开源爬虫一般会集成网页提取工具。主要支持两种规范:CSS SELECTOR 和 XPATH。至于哪个更好,我这里就不评论了。
5)爬虫是如何保存网页信息的?
有一些爬虫带有一个负责持久性的模块。例如,webmagic 有一个名为 pipeline 的模块。通过简单的配置,爬虫提取的信息可以持久化到文件、数据库等。还有一些爬虫不直接为用户提供数据持久化模块。比如 crawler4j 和 webcollector。让用户在网页处理模块中添加提交数据库的操作。至于用管道模块好不好,就类似于用ORM操作数据库好不好的问题,看你的业务。
6)爬虫被网站拦截了怎么办?
爬虫被网站阻塞,通常可以通过使用多个代理(随机代理)来解决。但是这些开源爬虫一般不直接支持随机代理的切换。因此,用户经常需要将获取到的代理放入一个全局数组中,并编写代码让代理随机获取(从数组中)。
7)网页可以调用爬虫吗?
爬虫的调用是在Web的服务器端调用的。您可以按照平时使用的方式使用它。可以使用这些爬虫。
8)爬虫速度怎么样?
单机开源爬虫的速度基本可以用到本地网速的极限。爬虫速度慢往往是因为用户减少了线程数,网速慢,或者数据持久化时与数据库的交互慢。而这些东西往往是由用户的机器和二次开发的代码决定的。这些开源爬虫的速度非常好。
9) 明明代码写对了,但是数据爬不出来。爬虫有问题吗?另一个爬虫可以解决吗?
如果代码写得正确,无法爬取数据,其他爬虫也将无法爬取。在这种情况下,要么是 网站 阻止了您,要么您抓取的数据是由 javascript 生成的。如果无法爬取数据,则无法通过更改爬虫来解决。
10)哪个爬虫可以判断网站是否已经爬完,哪个爬虫可以根据主题爬取?
爬虫无法判断网站是否已经爬完,只能尽量覆盖。
至于根据主题爬,爬虫把内容爬下来后就知道主题是什么了。因此,通常是整体爬下来,然后对内容进行过滤。如果爬取的范围太广,可以通过限制 URL 正则化来缩小范围。
11)哪个爬虫的设计模式和架构比较好?
设计模式是胡说八道。都说软件设计模式不错,软件开发后总结了几种设计模式。设计模式对软件开发没有指导意义。使用设计模式设计爬虫只会让爬虫的设计更加臃肿。
至于架构,目前开源爬虫主要是设计详细的数据结构,比如爬取线程池、任务队列等,大家都可以控制。爬虫的业务太简单了,用任何框架都谈不上。
所以对于 JAVA 开源爬虫,我认为,只要找到一个运行良好的。如果业务复杂,使用哪个爬虫,只能通过复杂的二次开发来满足需求。
3.3 非JAVA爬虫
在非JAVA语言编写的爬虫中,不乏优秀的爬虫。这里提取为一个类别,不是为了讨论爬虫本身的好坏,而是为了讨论larbin、scrapy等爬虫对开发成本的影响。
先说python爬虫,python用30行代码就可以完成JAVA 50行代码的任务。Python写代码确实很快,但是在调试代码阶段,调试python代码所消耗的时间往往比编码阶段节省的时间要多得多。使用python开发,为了保证程序的正确性和稳定性,需要编写更多的测试模块。当然,如果爬取规模不大,爬取业务也不复杂,用scrapy还是不错的,可以轻松完成爬取任务。
上图是Scrapy的架构图。绿线是数据流。从初始 URL 开始,Scheduler 会将其交给 Downloader 进行下载。下载完成后交给 Spider 进行分析,将要保存的数据发送到 Item Pipeline ,也就是对数据进行后处理。此外,可以在数据流通道中安装各种中间件,进行必要的处理。因此,在开发爬虫时,最好先规划好各个模块。我的做法是分别规划下载模块、爬取模块、调度模块、数据存储模块。
对于C++爬虫来说,学习**的成本会比较大。而且你不能只计算一个人的学习成本。如果软件需要一个团队来开发或交接,那是很多人学习的成本。软件调试不是那么容易。
还有一些ruby和php爬虫,这里就不多评价了。确实有一些非常小的data采集任务,在ruby或者php中都用得上。但是,要选择这些语言的开源爬虫,一方面需要调查相关的生态系统,另一方面,这些开源爬虫可能存在一些你找不到的bug(很少有人使用它们,和更少的信息)。
4、反爬虫技术
由于搜索引擎的普及,网络爬虫已经成为一种非常流行的网络技术。除了专注于搜索的谷歌、雅虎、微软和百度,几乎每个大型门户网站网站都有自己的搜索引擎。有几十个名字和成千上万个未知的名字。对于内容驱动的网站,网络爬虫的赞助是不可避免的。
一些智能搜索引擎爬虫的爬取频率比较合理,资源消耗也比较小,但是很多不良网络爬虫对网页的爬取能力很差,经常循环重复上百个请求。拿,这种爬虫对中小型网站来说往往是毁灭性的打击,尤其是一些缺乏爬虫编写经验的程序员编写的爬虫,破坏性极大,导致网站访问压力会很大非常大,这将导致 网站 访问缓慢甚至无法访问。
一般网站反爬虫从三个方面:用户请求的头文件、用户行为、网站目录和数据加载方式。前两种比较容易遇到,从这些角度来看,大部分网站都是反爬虫。会使用第三种使用ajax的网站,增加了爬取的难度。
4.1 反爬虫通过Headers
反爬取用户请求的头部是最常见的反爬取策略。很多网站会检测Headers的User-Agent,有的网站会检测Referer(有些资源的防盗链网站就是检测Referer)。如果遇到这样的反爬虫机制,可以直接在爬虫中添加Headers,将浏览器的User-Agent复制到爬虫的Headers中;或者将Referer值改为目标网站域名。对于检测Headers的反爬虫,在爬虫中修改或添加Headers可以很好的绕过。
[评论:它经常很容易被忽视。通过对请求的抓包分析,确定referer并添加到程序中模拟访问请求的header中]
4.2 基于用户行为的反爬虫
网站的另一部分是检测用户行为,比如同一个IP在短时间内多次访问同一个页面,或者同一个账号在短时间内多次执行相同的操作。
喜欢
不喜欢
你对这个答案的评价是什么? 查看全部
java爬虫抓取动态网页(Web网络爬虫系统的功能及应用)
1、爬虫技术概述
网络爬虫是根据一定的规则自动从万维网上爬取信息的程序或脚本。广泛应用于互联网搜索引擎或其他类似的网站,它可以自动采集它可以访问的页面的所有内容来获取或更新这些网站@的内容和检索方式>。从功能上来说,爬虫一般分为数据采集、处理、存储三部分。
传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在抓取网页的过程中,它不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。焦点爬虫的工作流程比较复杂。它需要按照一定的网页分析算法过滤掉与主题无关的链接,保留有用的链接,并放入等待抓取的URL队列中。然后,它会根据一定的搜索策略从队列中选择下一个要爬取的网页URL,并重复上述过程,直到达到系统的一定条件并停止。另外,爬虫爬取的所有网页都会被系统存储,进行一定的分析、过滤、索引,以供后续查询和检索;对于重点爬虫来说,这个过程中得到的分析结果也可能对后续的爬取过程给出反馈和指导。
与通用网络爬虫相比,聚焦爬虫还需要解决三个主要问题:
(1) 获取目标的描述或定义;
(2) 网页或数据的分析和过滤;
(3) URL 的搜索策略。
2、爬虫原理
2.1 网络爬虫原理
网络爬虫系统的功能是下载网页数据,为搜索引擎系统提供数据源。许多大型网络搜索引擎系统被称为基于Web数据的搜索引擎系统采集,如Google、百度等。这显示了网络爬虫系统在搜索引擎中的重要性。除了供用户阅读的文字信息外,网页还收录一些超链接信息。网络爬虫系统通过网页中的超链接信息不断获取网络上的其他网页。正是因为这个采集进程像爬虫或者蜘蛛一样在网络上漫游,所以才叫做网络爬虫系统或者网络蜘蛛系统,英文叫Spider或者Crawler。
2.2 网络爬虫系统的工作原理
在网络爬虫的系统框架中,主要流程由控制器、解析器和资源库三部分组成。控制器的主要工作是为多个线程中的每个爬虫线程分配工作任务。解析器的主要工作是下载网页和处理页面,主要是处理一些JS脚本标签、CSS代码内容、空格字符、HTML标签等。爬虫的基本工作是由解析器完成的。资源库用于存储下载的网络资源。通常使用大型数据库,例如 Oracle 数据库来存储和索引它。
控制器
控制器是网络爬虫的第一个控制器。主要负责根据系统发送的URL链接分配线程,然后启动线程调用爬虫爬取网页。
解析器
解析器负责网络爬虫的主要部分。它的主要任务是:下载网页的功能,处理网页的文本,如过滤,提取特殊的HTML标签,分析数据。
资源库
它主要是一个容器,用于存储从网页下载的数据记录,并为索引生成提供目标源。大中型数据库产品包括:Oracle、Sql Server等。
网络爬虫系统一般会选择一些比较重要的出度(网页中超链接数)网站较大的URL作为种子URL集。网络爬虫系统使用这些种子集作为初始 URL 来开始数据爬取。因为网页中收录链接信息,所以会通过已有网页的URL获取一些新的URL。网页之间的指向结构可以看作是一片森林。每个种子 URL 对应的网页是森林中一棵树的根节点。. 这样,网络爬虫系统就可以按照广度优先算法或深度优先算法遍历所有网页。由于深度优先搜索算法可能导致爬虫系统陷入网站内部,不利于搜索距离网站首页比较近的网页信息,一般采用广度优先搜索算法采集网页。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。
网络爬虫的基本工作流程如下:
1.首先选择一个精心挑选的种子 URL 的子集;
2.将这些网址放入待抓取的网址队列中;
3. 从待爬取URL队列中取出待爬取的URL,解析DNS,获取主机IP,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URLs 队列;
4.分析已经爬取的URL队列中的URL,分析其中的其他URL,将这些URL放入待爬取的URL队列,从而进入下一个循环。
2.3 爬取策略
在爬虫系统中,待爬取的 URL 队列是一个重要的部分。待爬取的URL队列中的URL的排列顺序也是一个重要的问题,因为它涉及到先爬到哪个页面,再爬到哪个页面。确定这些 URL 排列顺序的方法称为爬取策略。下面重点介绍几种常见的爬取策略:
2.3.1 深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,每次一个链接跟踪每个链接,处理完该行后移动到下一个起始页,并继续跟踪该链接。我们以下图为例:
遍历的路径:AFG EHI BCD
2.3.2 广度优先遍历策略
广度优先遍历策略的基本思想是将新下载的网页中找到的链接直接放到待爬取的URL队列的末尾。也就是说,网络爬虫会先爬取起始网页链接的所有网页,然后选择其中一个链接的网页,继续爬取该网页链接的所有网页。或者以上图为例:
遍历路径:ABCDEF GHI
2.3.3 反向链接策略
反向链接数是指从其他网页指向一个网页的链接数。反向链接的数量表示网页内容被他人推荐的程度。因此,在很多情况下,搜索引擎的爬取系统会使用这个指标来评估网页的重要性,从而确定不同网页的爬取顺序。
在真实的网络环境中,由于广告链接和作弊链接的存在,反向链接的数量并不能完全等同于他人的重要性。因此,搜索引擎倾向于考虑一些可靠的反向链接计数。
2.3.4 部分PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于下载的网页,与待爬取的URL队列中的URL一起,形成一组网页,计算每个页面的PageRank值. URL 按 PageRank 值排序,并按该顺序抓取页面。
如果每次爬取一个页面都重新计算一次PageRank值,折中的解决方案是:每爬完K个页面,重新计算一次PageRank值。但是这种情况还是有一个问题:对于下载页面中分析的链接,也就是我们前面提到的未知网页部分,暂时没有PageRank值。为了解决这个问题,会给这些页面一个临时的PageRank值:将这个网页所有传入链接传入的PageRank值聚合起来,从而形成未知页面的PageRank值,从而参与排序。
2.3.5 OPIC 政策方针
该算法实际上为页面分配了一个重要性分数。在算法开始之前,所有页面都会获得相同的初始现金。当某个页面P被下载时,P的现金分配给从P分析的所有链接,P的现金被清空。根据现金数量对待爬取URL队列中的所有页面进行排序。
2.3.6 大网站优先策略
所有待爬取的URL队列中的网页都按照它们所属的网站进行分类。网站需要下载的页面较多,请先下载。这种策略也称为大站点优先策略。
3、爬虫分类
我应该选择 Nutch、Crawler4j、WebMagic、scrapy、WebCollector 还是其他来开发网络爬虫?上面提到的爬虫类,基本上可以分为三类:
(1)分布式爬虫:Nutch
(2)JAVA 爬虫:Crawler4j、WebMagic、WebCollector
(3)非JAVA爬虫:scrapy(基于Python语言开发)
3.1 分布式爬虫
爬虫使用分布式,主要解决两个问题:
1)海量网址管理
2)网速
现在比较流行的分布式爬虫是Apache的Nutch。但是对于大多数用户来说,Nutch 是这些爬虫中最差的选择,原因如下:
1)Nutch 是为搜索引擎设计的爬虫。大多数用户需要一个爬虫来进行准确的数据爬取(精细提取)。Nutch 运行的三分之二的流程是为搜索引擎设计的。提取意义不大。换句话说,使用 Nutch 进行数据提取会在不必要的计算上浪费大量时间。而如果你试图通过Nutch的二次开发使其适合提取业务,你基本上会破坏Nutch的框架,将Nutch改得面目全非,并且有能力修改Nutch,还不如自己写一个新的. 分布式爬虫框架。
2)Nutch 依赖hadoop 运行,hadoop 本身消耗大量时间。如果集群机器数量少,爬取速度不如单机爬虫快。
3)虽然Nutch有一套插件机制,但还是作为亮点来宣传的。可以看到一些开源的Nutch插件,提供精准提取功能。但是任何开发过 Nutch 插件的人都知道 Nutch 的插件系统有多糟糕。使用反射机制加载和调用插件,使得程序的编写和调试变得异常困难,更不用说在其上开发复杂的提取系统了。并且 Nutch 没有提供对应的插件挂载点进行精细提取。Nutch的插件只有五六个挂载点,而这五六个挂载点都是给搜索引擎服务的,不提供细提取的挂载点。Nutch 的大部分精炼提取插件都安装在“解析器”安装点上。这个挂载点其实是用来解析链接(为后续爬取提供URL)和提供一些搜索引擎的。易于提取的网页信息(元信息、网页文本)。
4)使用Nutch进行爬虫的二次开发,编写和调试爬虫所需的时间往往是单机爬虫所需时间的十倍以上。学习 Nutch 源码的成本非常高,更何况团队中的每个人都必须了解 Nutch 源码。在调试过程中,会出现程序本身以外的各种问题(hadoop问题、hbase问题)。
5)很多人说Nutch2有gora,可以将数据持久化到avro文件、hbase、mysql等,其实很多人理解错了。这里所说的持久化数据是指在avro、hbase、mysql中存储URL信息(URL管理所需的数据)。不是您要提取的结构化数据。事实上,对于大多数人来说,URL 信息存在于何处并不重要。
6)Nutch2 的版本目前不适合开发。Nutch的官方稳定版是nutch2.2.1,但是这个版本绑定了gora-0.3。如果要使用hbase和nutch(大多数人使用nutch2是为了使用hbase),只能使用版本0.90左右的hbase,相应地,将hadoop版本降低到hadoop 0.左右@>2。而且nutch2的官方教程也颇具误导性。Nutch2的教程有两个,分别是Nutch1.x和Nutch2.x。这个Nutch2.x官网是为了支持hbase0.94而写的。但其实这个Nutch2.x是指Nutch2.3之前和Nutch2.2.1之后的一个版本,在官方SVN中不断更新。而且它'
所以,如果你不是搜索引擎,尽量不要选择 Nutch 作为爬虫。一些团队喜欢跟风。他们坚持选择Nutch来开发精制履带。事实上,这是针对Nutch的声誉。当然,最终的结果往往是项目延期。
如果你在做搜索引擎,Nutch1.x 是一个非常不错的选择。Nutch1.x 和 solr 或 es 可以组成一个非常强大的搜索引擎。如果必须使用 Nutch2,建议等到 Nutch2.3 发布。当前的 Nutch2 是一个非常不稳定的版本。
3.2 JAVA爬虫
在这里,将JAVA爬虫划分为一个单独的类别,因为JAVA在网络爬虫的生态系统中非常完善。相关资料也是最全的。这里可能有争议,我只是随便说说。
其实开源网络爬虫(框架)的开发很简单,难点和复杂的问题已经被前人解决了(比如DOM树解析定位、字符集检测、海量URL去重),可以说没有技术含量。包括Nutch,其实Nutch的技术难点就是开发hadoop,代码本身也很简单。从某种意义上说,网络爬虫类似于遍历本机的文件以查找文件中的信息。没有任何困难。选择开源爬虫框架的原因是为了省事。比如爬虫的URL管理、线程池等模块,任何人都可以做,但是需要一段时间的调试和修改才能稳定下来。
对于爬虫的功能。用户比较关心的问题往往是:
1)爬虫是否支持多线程,爬虫是否可以使用代理,爬虫是否可以爬取重复数据,爬虫是否可以爬取JS生成的信息?
不支持多线程、不支持代理、不能过滤重复URL的不叫开源爬虫,叫循环执行http请求。
js生成的信息能否被爬取与爬虫本身关系不大。爬虫主要负责遍历网站和下载页面。爬取js产生的信息与网页信息提取模块有关,往往需要通过模拟浏览器(htmlunit、selenium)来完成。这些模拟浏览器通常需要花费大量时间来处理一个页面。因此,一种策略是利用这些爬虫遍历网站,当遇到需要解析的页面时,将网页的相关信息提交给模拟浏览器,完成对JS生成信息的提取。
2)爬虫可以抓取ajax信息吗?
网页上有一些异步加载的数据。爬取数据有两种方式:使用模拟浏览器(问题1中描述),或者分析ajax的http请求,自己生成ajax请求的url,获取返回的数据。如果你自己生成ajax请求,那么使用开源爬虫有什么意义呢?其实就是利用开源爬虫的线程池和URL管理功能(比如断点爬取)。
如果我已经可以生成我需要的ajax请求(列表),我该如何使用这些爬虫来爬取这些请求呢?
爬虫往往被设计成广度遍历或深度遍历的方式来遍历静态或动态页面。爬取ajax信息属于深网(deep web)的范畴,虽然大部分爬虫并不直接支持。但它也可以通过某些方式完成。例如,WebCollector 使用广度遍历来遍历 网站。爬虫的第一轮爬取就是爬取种子集(seeds)中的所有url。简单来说就是将生成的ajax请求作为种子,放入爬虫中。使用爬虫对这些种子进行深度为 1 的广度遍历(默认为广度遍历)。
3)爬虫如何爬取待登录的网站?
这些开源爬虫都支持在爬取时指定cookies,而模拟登录主要依赖cookies。至于如何获取cookies,就不是爬虫管理的问题了。您可以手动获取cookies,使用http请求模拟登录,或者使用模拟浏览器自动登录。
4)爬虫如何从网页中提取信息?
开源爬虫一般会集成网页提取工具。主要支持两种规范:CSS SELECTOR 和 XPATH。至于哪个更好,我这里就不评论了。
5)爬虫是如何保存网页信息的?
有一些爬虫带有一个负责持久性的模块。例如,webmagic 有一个名为 pipeline 的模块。通过简单的配置,爬虫提取的信息可以持久化到文件、数据库等。还有一些爬虫不直接为用户提供数据持久化模块。比如 crawler4j 和 webcollector。让用户在网页处理模块中添加提交数据库的操作。至于用管道模块好不好,就类似于用ORM操作数据库好不好的问题,看你的业务。
6)爬虫被网站拦截了怎么办?
爬虫被网站阻塞,通常可以通过使用多个代理(随机代理)来解决。但是这些开源爬虫一般不直接支持随机代理的切换。因此,用户经常需要将获取到的代理放入一个全局数组中,并编写代码让代理随机获取(从数组中)。
7)网页可以调用爬虫吗?
爬虫的调用是在Web的服务器端调用的。您可以按照平时使用的方式使用它。可以使用这些爬虫。
8)爬虫速度怎么样?
单机开源爬虫的速度基本可以用到本地网速的极限。爬虫速度慢往往是因为用户减少了线程数,网速慢,或者数据持久化时与数据库的交互慢。而这些东西往往是由用户的机器和二次开发的代码决定的。这些开源爬虫的速度非常好。
9) 明明代码写对了,但是数据爬不出来。爬虫有问题吗?另一个爬虫可以解决吗?
如果代码写得正确,无法爬取数据,其他爬虫也将无法爬取。在这种情况下,要么是 网站 阻止了您,要么您抓取的数据是由 javascript 生成的。如果无法爬取数据,则无法通过更改爬虫来解决。
10)哪个爬虫可以判断网站是否已经爬完,哪个爬虫可以根据主题爬取?
爬虫无法判断网站是否已经爬完,只能尽量覆盖。
至于根据主题爬,爬虫把内容爬下来后就知道主题是什么了。因此,通常是整体爬下来,然后对内容进行过滤。如果爬取的范围太广,可以通过限制 URL 正则化来缩小范围。
11)哪个爬虫的设计模式和架构比较好?
设计模式是胡说八道。都说软件设计模式不错,软件开发后总结了几种设计模式。设计模式对软件开发没有指导意义。使用设计模式设计爬虫只会让爬虫的设计更加臃肿。
至于架构,目前开源爬虫主要是设计详细的数据结构,比如爬取线程池、任务队列等,大家都可以控制。爬虫的业务太简单了,用任何框架都谈不上。
所以对于 JAVA 开源爬虫,我认为,只要找到一个运行良好的。如果业务复杂,使用哪个爬虫,只能通过复杂的二次开发来满足需求。
3.3 非JAVA爬虫
在非JAVA语言编写的爬虫中,不乏优秀的爬虫。这里提取为一个类别,不是为了讨论爬虫本身的好坏,而是为了讨论larbin、scrapy等爬虫对开发成本的影响。
先说python爬虫,python用30行代码就可以完成JAVA 50行代码的任务。Python写代码确实很快,但是在调试代码阶段,调试python代码所消耗的时间往往比编码阶段节省的时间要多得多。使用python开发,为了保证程序的正确性和稳定性,需要编写更多的测试模块。当然,如果爬取规模不大,爬取业务也不复杂,用scrapy还是不错的,可以轻松完成爬取任务。
上图是Scrapy的架构图。绿线是数据流。从初始 URL 开始,Scheduler 会将其交给 Downloader 进行下载。下载完成后交给 Spider 进行分析,将要保存的数据发送到 Item Pipeline ,也就是对数据进行后处理。此外,可以在数据流通道中安装各种中间件,进行必要的处理。因此,在开发爬虫时,最好先规划好各个模块。我的做法是分别规划下载模块、爬取模块、调度模块、数据存储模块。
对于C++爬虫来说,学习**的成本会比较大。而且你不能只计算一个人的学习成本。如果软件需要一个团队来开发或交接,那是很多人学习的成本。软件调试不是那么容易。
还有一些ruby和php爬虫,这里就不多评价了。确实有一些非常小的data采集任务,在ruby或者php中都用得上。但是,要选择这些语言的开源爬虫,一方面需要调查相关的生态系统,另一方面,这些开源爬虫可能存在一些你找不到的bug(很少有人使用它们,和更少的信息)。
4、反爬虫技术
由于搜索引擎的普及,网络爬虫已经成为一种非常流行的网络技术。除了专注于搜索的谷歌、雅虎、微软和百度,几乎每个大型门户网站网站都有自己的搜索引擎。有几十个名字和成千上万个未知的名字。对于内容驱动的网站,网络爬虫的赞助是不可避免的。
一些智能搜索引擎爬虫的爬取频率比较合理,资源消耗也比较小,但是很多不良网络爬虫对网页的爬取能力很差,经常循环重复上百个请求。拿,这种爬虫对中小型网站来说往往是毁灭性的打击,尤其是一些缺乏爬虫编写经验的程序员编写的爬虫,破坏性极大,导致网站访问压力会很大非常大,这将导致 网站 访问缓慢甚至无法访问。
一般网站反爬虫从三个方面:用户请求的头文件、用户行为、网站目录和数据加载方式。前两种比较容易遇到,从这些角度来看,大部分网站都是反爬虫。会使用第三种使用ajax的网站,增加了爬取的难度。
4.1 反爬虫通过Headers
反爬取用户请求的头部是最常见的反爬取策略。很多网站会检测Headers的User-Agent,有的网站会检测Referer(有些资源的防盗链网站就是检测Referer)。如果遇到这样的反爬虫机制,可以直接在爬虫中添加Headers,将浏览器的User-Agent复制到爬虫的Headers中;或者将Referer值改为目标网站域名。对于检测Headers的反爬虫,在爬虫中修改或添加Headers可以很好的绕过。
[评论:它经常很容易被忽视。通过对请求的抓包分析,确定referer并添加到程序中模拟访问请求的header中]
4.2 基于用户行为的反爬虫
网站的另一部分是检测用户行为,比如同一个IP在短时间内多次访问同一个页面,或者同一个账号在短时间内多次执行相同的操作。
喜欢
不喜欢
你对这个答案的评价是什么?
java爬虫抓取动态网页(之前第一篇教程.js爬虫入门(一)爬取静态页面)
网站优化 • 优采云 发表了文章 • 0 个评论 • 47 次浏览 • 2022-02-01 18:11
之前的第一篇爬虫教程,Node.js爬虫介绍(一)爬取静态页面讲解静态网页的爬取,很简单,但是如果遇到一些动态网页(ajax),可以直接用之前发送请求的方法我们都拿不到我们想要的数据,这时候需要爬取动态网页,selenium和puppeteer都不错。
这里推荐使用puppeteer,不为别的,只因为他是谷歌自己的,一直在维护更新。以下是翻译的官方文档介绍
Puppeteer 是一个 Node 库,提供一系列高级接口,通过 DevTools(开发者工具)协议控制 Chrome 或 Chromium(谷歌开源)。它默认以无头模式运行(无浏览器 UI),也可以通过配置以正常模式运行。
它可用于:
首先,我们必须在使用它之前安装它。默认安装会附带下载最新的 Chromium,大小约为 300M。
npm install puppeteer
如果本地已经有较新版本的chrome,可以只安装core版本,但是启动puppeteer时需要配置本地chrome的路径。
npm install puppeteer-core // 核心版本
假设我们现在要爬取拉狗网的前端招聘信息。这是一个动态页面。使用下面的示例尝试抓取。
因为chrome操作都是异步操作,为了避免回调地狱,推荐使用es7的async await。这种语法具有高度可读性,官方文档也是如此。
首先使用 puppeteer 启动浏览器并打开该动态页面
这里需要注意的是,如果使用的是本地浏览器,需要在启动浏览器配置中传入本地chrome路径
const browser = await puppeteer.launch({
executablePath: 'C:/Users/Administrator/AppData/Local/Google/Chrome/Application/chrome.exe'
})
在chrome环境中执行函数获取需要的数据然后返回节点的执行环境
上图是我们需要的数据的dom位置。在chrome环境执行的函数中,我们需要获取并整理需要的数据。
let list = document.querySelectorAll('.s_position_list .item_con_list li')
let res = []
for (let i = 0; i < list.length; i++) {
res.push({
name: list[i].getAttribute('data-positionname'),
company: list[i].getAttribute('data-company'),
salary: list[i].getAttribute('data-salary'),
require: list[i].querySelector('.li_b_l').childNodes[4].textContent.replace(/ |\n/g, ''),
})
}
return res
这里有一个调试技巧,获取数据的函数可以直接写在chrome的控制台中,方便调试
最后附上完整代码
const puppeteer = require('puppeteer');
(async () => {
// 启动浏览器
const browser = await puppeteer.launch({
headless: false, // 默认是无头模式,这里为了示范所以使用正常模式
})
// 控制浏览器打开新标签页面
const page = await browser.newPage()
// 在新标签中打开要爬取的网页
await page.goto('https://www.lagou.com/jobs/lis ... %2339;)
// 使用evaluate方法在浏览器中执行传入函数(完全的浏览器环境,所以函数内可以直接使用window、document等所有对象和方法)
let data = await page.evaluate(() => {
let list = document.querySelectorAll('.s_position_list .item_con_list li')
let res = []
for (let i = 0; i < list.length; i++) {
res.push({
name: list[i].getAttribute('data-positionname'),
company: list[i].getAttribute('data-company'),
salary: list[i].getAttribute('data-salary'),
require: list[i].querySelector('.li_b_l').childNodes[4].textContent.replace(/ |\n/g, ''),
})
}
return res
})
console.log(data)
})()
运行结果
动态网页的爬取到这里也已经完成了,但是puppeteer功能远不止这些,它还有很多强大的API可以使用。您可以转到官方文档。
第三期会讲到如何定时执行爬虫并存入数据库。 查看全部
java爬虫抓取动态网页(之前第一篇教程.js爬虫入门(一)爬取静态页面)
之前的第一篇爬虫教程,Node.js爬虫介绍(一)爬取静态页面讲解静态网页的爬取,很简单,但是如果遇到一些动态网页(ajax),可以直接用之前发送请求的方法我们都拿不到我们想要的数据,这时候需要爬取动态网页,selenium和puppeteer都不错。
这里推荐使用puppeteer,不为别的,只因为他是谷歌自己的,一直在维护更新。以下是翻译的官方文档介绍
Puppeteer 是一个 Node 库,提供一系列高级接口,通过 DevTools(开发者工具)协议控制 Chrome 或 Chromium(谷歌开源)。它默认以无头模式运行(无浏览器 UI),也可以通过配置以正常模式运行。
它可用于:
首先,我们必须在使用它之前安装它。默认安装会附带下载最新的 Chromium,大小约为 300M。
npm install puppeteer
如果本地已经有较新版本的chrome,可以只安装core版本,但是启动puppeteer时需要配置本地chrome的路径。
npm install puppeteer-core // 核心版本
假设我们现在要爬取拉狗网的前端招聘信息。这是一个动态页面。使用下面的示例尝试抓取。
因为chrome操作都是异步操作,为了避免回调地狱,推荐使用es7的async await。这种语法具有高度可读性,官方文档也是如此。
首先使用 puppeteer 启动浏览器并打开该动态页面
这里需要注意的是,如果使用的是本地浏览器,需要在启动浏览器配置中传入本地chrome路径
const browser = await puppeteer.launch({
executablePath: 'C:/Users/Administrator/AppData/Local/Google/Chrome/Application/chrome.exe'
})
在chrome环境中执行函数获取需要的数据然后返回节点的执行环境

上图是我们需要的数据的dom位置。在chrome环境执行的函数中,我们需要获取并整理需要的数据。
let list = document.querySelectorAll('.s_position_list .item_con_list li')
let res = []
for (let i = 0; i < list.length; i++) {
res.push({
name: list[i].getAttribute('data-positionname'),
company: list[i].getAttribute('data-company'),
salary: list[i].getAttribute('data-salary'),
require: list[i].querySelector('.li_b_l').childNodes[4].textContent.replace(/ |\n/g, ''),
})
}
return res
这里有一个调试技巧,获取数据的函数可以直接写在chrome的控制台中,方便调试
最后附上完整代码
const puppeteer = require('puppeteer');
(async () => {
// 启动浏览器
const browser = await puppeteer.launch({
headless: false, // 默认是无头模式,这里为了示范所以使用正常模式
})
// 控制浏览器打开新标签页面
const page = await browser.newPage()
// 在新标签中打开要爬取的网页
await page.goto('https://www.lagou.com/jobs/lis ... %2339;)
// 使用evaluate方法在浏览器中执行传入函数(完全的浏览器环境,所以函数内可以直接使用window、document等所有对象和方法)
let data = await page.evaluate(() => {
let list = document.querySelectorAll('.s_position_list .item_con_list li')
let res = []
for (let i = 0; i < list.length; i++) {
res.push({
name: list[i].getAttribute('data-positionname'),
company: list[i].getAttribute('data-company'),
salary: list[i].getAttribute('data-salary'),
require: list[i].querySelector('.li_b_l').childNodes[4].textContent.replace(/ |\n/g, ''),
})
}
return res
})
console.log(data)
})()
运行结果

动态网页的爬取到这里也已经完成了,但是puppeteer功能远不止这些,它还有很多强大的API可以使用。您可以转到官方文档。
第三期会讲到如何定时执行爬虫并存入数据库。
java爬虫抓取动态网页(什么是Webmagic.要使用Webmagic?期刊版面内容表表 )
网站优化 • 优采云 发表了文章 • 0 个评论 • 51 次浏览 • 2022-02-01 06:15
)
一、什么是 Webmagic。
要使用 Webmagic,首先需要了解 Webmagic 是什么。
webmagic 是一个开源的 Java 垂直爬虫框架。目标是简化爬虫的开发过程,让开发者专注于逻辑功能的开发。webmagic主要由Downloader(下载器)、PageProcesser(解析器)、Schedule(调度器)和Pipeline(管道)组成。
webmagic采用完全模块化设计,功能覆盖爬虫全生命周期(链接提取、页面下载、内容提取、持久化),支持多线程爬取、分布式爬取,并支持自动重试、自定义UA/等功能饼干。
webmagic 收录页面提取功能,开发者可以使用 css 选择器、xpath 和正则表达式提取链接和内容,并支持多个选择器链调用。
二、示例代码
(1)pom.xml 文件增加了新的依赖
us.codecraft`这里写代码片` webmagic-core
0.5.3
us.codecraft
webmagic-extension
0.5.3
(2)Scheduling定时任务设定,也可称为调度器。
import javax.annotation.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import org.springframework.transaction.annotation.Transactional;import com.zhibo.xmt.common.webmagic.xpager.popeline.XpaperZgtcbPopeline;import com.zhibo.xmt.common.webmagic.xpager.processor.XpaperZgtcbProcessor;import us.codecraft.webmagic.Spider;/**
* 爬取 xpaper http://i.xpaper.net/cnsports 版面信息数据
* 每周 二 、 四、日发布新期刊
* @author Bruce
*
*/@Component@EnableSchedulingpublic class XpaperWebmagicSchedulingConfig {
private final Logger logger = LoggerFactory.getLogger(XpaperWebmagicSchedulingConfig.class); public static final String BASE_URL = "http://i.xpaper.net/cnsports"; @Resource
private XpaperZgtcbPopeline xpaperZgtcbPopeline; /**
* 中国体彩报 xpaper全媒体数字报 版面内容抓取
*/
/**
* "0 0/1 18 * * ?" 每天18:00到18:59 没分钟执行一次
*
* "0 10 4 ? * *" 每天上午4:10触发
*/
@Transactional
@Scheduled(cron = "0 10 4 ? * *") public void createLotteryInfo(){
System.out.println("中国体彩报 xpaper全媒体数字报 版面内容抓取"); long startTime, endTime;
System.out.println("【爬虫开始】");
startTime = System.currentTimeMillis();
logger.info("爬取地址:" + BASE_URL); try {
Spider spider = Spider.create(new XpaperZgtcbProcessor());
spider.addUrl(BASE_URL);
spider.addPipeline(xpaperZgtcbPopeline);
spider.thread(5);
spider.setExitWhenComplete(true);
spider.start();
spider.stop();
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
endTime = System.currentTimeMillis();
System.out.println("【爬虫结束】");
System.out.println("中国体彩报 xpaper全媒体数字报 版面内容抓取耗时约" + ((endTime - startTime) / 1000) + "秒,已保存到数据库.");
}
}
(3)XpaperZgtcbProcessor解析器,解析要爬取的页面
<p>import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import com.zhibo.xmt.common.enums.common.EnumCommonStatus;import com.zhibo.xmt.common.util.DateUtil;import com.zhibo.xmt.common.vo.pagesub.Journal;import com.zhibo.xmt.common.vo.pagesub.JournalPage;import us.codecraft.webmagic.Page;import us.codecraft.webmagic.Site;import us.codecraft.webmagic.processor.PageProcessor;import us.codecraft.webmagic.selector.Selectable;/**
* 中国体彩报 xpaper全媒体数字报 版面内容抓取
* http://i.xpaper.net/cnsports
* @author Bruce
*
*/@Component
public class XpaperZgtcbProcessor implements PageProcessor{
private static Logger logger = LoggerFactory.getLogger(XpaperZgtcbProcessor.class);
// 正则表达式\\. \\转义java中的\ \.转义正则中的.
// 主域名
public static final String BASE_URL = "http://i.xpaper.net/cnsports";
private Site site = Site.me() .setDomain(BASE_URL) .setSleepTime(1000) .setRetryTimes(30) .setCharset("utf-8") .setTimeOut(30000) .setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31");
@Override
public Site getSite() {
return site;
}
@Override
public void process(Page page) {
if (page.getUrl().regex(BASE_URL).match()) {
String contentTitle = page.getHtml().xpath("//title/text()").toString();
/**
* System.out.println("issue:" + issue);
System.out.println("issueDesc:" + issueDesc);
System.out.println("contentTitle:" + contentTitle);
* contentTitle:中国体彩报 - 第1151期 - 第01版 - A1
issue: 1151
issueDesc:中国体彩报 - 第1151期
*/
String[] contentTitles = contentTitle.trim().split("-");
String issueStr = contentTitles[1].replaceAll("第", "").replaceAll("期", "").replaceAll(" ", "").trim().replaceAll("\\s*", "");
String issue = new String(issueStr);
//由于里面有空格,因此使用了多种方式去空格。
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(issue);
issue = m.replaceAll("");
issue = issue.replaceAll("\\u00A0","");
String issueDesc = contentTitles[0] + "-" + contentTitles[1];
Journal journal = new Journal();
journal.setTitle(issueDesc);
journal.setTitleDesc(contentTitle);
journal.setIssue(issue);
journal.setDate(DateUtil.getDateByFormat(DateUtil.getDateByFormat(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd"));
journal.setDateStr(DateUtil.getDateByFormat(new Date(), "yyyy-MM-dd"));
journal.setType(1);
journal.setStatus(EnumCommonStatus.NORMAL.getValue());
journal.setGrabDate(new Date());
journal.setCreatedAt(new Date());
journal.setUpdatedAt(new Date());
logger.info("期刊数据:" + journal.toString());
List list = page.getHtml().xpath("//div[@id='m1']/a").nodes();
if(list != null && list.size() > 0){
List journalPages = new ArrayList();
for(int i = 0; i < list.size(); i++){
Selectable s = list.get(i);
String link = s.links().toString();
String titleStr = s.xpath("//b/text()").toString();
if(StringUtils.isBlank(titleStr)){
titleStr = s.toString().split(">")[1].replaceAll(" 查看全部
java爬虫抓取动态网页(什么是Webmagic.要使用Webmagic?期刊版面内容表表
)
一、什么是 Webmagic。
要使用 Webmagic,首先需要了解 Webmagic 是什么。
webmagic 是一个开源的 Java 垂直爬虫框架。目标是简化爬虫的开发过程,让开发者专注于逻辑功能的开发。webmagic主要由Downloader(下载器)、PageProcesser(解析器)、Schedule(调度器)和Pipeline(管道)组成。
webmagic采用完全模块化设计,功能覆盖爬虫全生命周期(链接提取、页面下载、内容提取、持久化),支持多线程爬取、分布式爬取,并支持自动重试、自定义UA/等功能饼干。
webmagic 收录页面提取功能,开发者可以使用 css 选择器、xpath 和正则表达式提取链接和内容,并支持多个选择器链调用。
二、示例代码
(1)pom.xml 文件增加了新的依赖
us.codecraft`这里写代码片` webmagic-core
0.5.3
us.codecraft
webmagic-extension
0.5.3
(2)Scheduling定时任务设定,也可称为调度器。
import javax.annotation.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import org.springframework.transaction.annotation.Transactional;import com.zhibo.xmt.common.webmagic.xpager.popeline.XpaperZgtcbPopeline;import com.zhibo.xmt.common.webmagic.xpager.processor.XpaperZgtcbProcessor;import us.codecraft.webmagic.Spider;/**
* 爬取 xpaper http://i.xpaper.net/cnsports 版面信息数据
* 每周 二 、 四、日发布新期刊
* @author Bruce
*
*/@Component@EnableSchedulingpublic class XpaperWebmagicSchedulingConfig {
private final Logger logger = LoggerFactory.getLogger(XpaperWebmagicSchedulingConfig.class); public static final String BASE_URL = "http://i.xpaper.net/cnsports"; @Resource
private XpaperZgtcbPopeline xpaperZgtcbPopeline; /**
* 中国体彩报 xpaper全媒体数字报 版面内容抓取
*/
/**
* "0 0/1 18 * * ?" 每天18:00到18:59 没分钟执行一次
*
* "0 10 4 ? * *" 每天上午4:10触发
*/
@Transactional
@Scheduled(cron = "0 10 4 ? * *") public void createLotteryInfo(){
System.out.println("中国体彩报 xpaper全媒体数字报 版面内容抓取"); long startTime, endTime;
System.out.println("【爬虫开始】");
startTime = System.currentTimeMillis();
logger.info("爬取地址:" + BASE_URL); try {
Spider spider = Spider.create(new XpaperZgtcbProcessor());
spider.addUrl(BASE_URL);
spider.addPipeline(xpaperZgtcbPopeline);
spider.thread(5);
spider.setExitWhenComplete(true);
spider.start();
spider.stop();
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
endTime = System.currentTimeMillis();
System.out.println("【爬虫结束】");
System.out.println("中国体彩报 xpaper全媒体数字报 版面内容抓取耗时约" + ((endTime - startTime) / 1000) + "秒,已保存到数据库.");
}
}
(3)XpaperZgtcbProcessor解析器,解析要爬取的页面
<p>import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import com.zhibo.xmt.common.enums.common.EnumCommonStatus;import com.zhibo.xmt.common.util.DateUtil;import com.zhibo.xmt.common.vo.pagesub.Journal;import com.zhibo.xmt.common.vo.pagesub.JournalPage;import us.codecraft.webmagic.Page;import us.codecraft.webmagic.Site;import us.codecraft.webmagic.processor.PageProcessor;import us.codecraft.webmagic.selector.Selectable;/**
* 中国体彩报 xpaper全媒体数字报 版面内容抓取
* http://i.xpaper.net/cnsports
* @author Bruce
*
*/@Component
public class XpaperZgtcbProcessor implements PageProcessor{
private static Logger logger = LoggerFactory.getLogger(XpaperZgtcbProcessor.class);
// 正则表达式\\. \\转义java中的\ \.转义正则中的.
// 主域名
public static final String BASE_URL = "http://i.xpaper.net/cnsports";
private Site site = Site.me() .setDomain(BASE_URL) .setSleepTime(1000) .setRetryTimes(30) .setCharset("utf-8") .setTimeOut(30000) .setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31");
@Override
public Site getSite() {
return site;
}
@Override
public void process(Page page) {
if (page.getUrl().regex(BASE_URL).match()) {
String contentTitle = page.getHtml().xpath("//title/text()").toString();
/**
* System.out.println("issue:" + issue);
System.out.println("issueDesc:" + issueDesc);
System.out.println("contentTitle:" + contentTitle);
* contentTitle:中国体彩报 - 第1151期 - 第01版 - A1
issue: 1151
issueDesc:中国体彩报 - 第1151期
*/
String[] contentTitles = contentTitle.trim().split("-");
String issueStr = contentTitles[1].replaceAll("第", "").replaceAll("期", "").replaceAll(" ", "").trim().replaceAll("\\s*", "");
String issue = new String(issueStr);
//由于里面有空格,因此使用了多种方式去空格。
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(issue);
issue = m.replaceAll("");
issue = issue.replaceAll("\\u00A0","");
String issueDesc = contentTitles[0] + "-" + contentTitles[1];
Journal journal = new Journal();
journal.setTitle(issueDesc);
journal.setTitleDesc(contentTitle);
journal.setIssue(issue);
journal.setDate(DateUtil.getDateByFormat(DateUtil.getDateByFormat(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd"));
journal.setDateStr(DateUtil.getDateByFormat(new Date(), "yyyy-MM-dd"));
journal.setType(1);
journal.setStatus(EnumCommonStatus.NORMAL.getValue());
journal.setGrabDate(new Date());
journal.setCreatedAt(new Date());
journal.setUpdatedAt(new Date());
logger.info("期刊数据:" + journal.toString());
List list = page.getHtml().xpath("//div[@id='m1']/a").nodes();
if(list != null && list.size() > 0){
List journalPages = new ArrayList();
for(int i = 0; i < list.size(); i++){
Selectable s = list.get(i);
String link = s.links().toString();
String titleStr = s.xpath("//b/text()").toString();
if(StringUtils.isBlank(titleStr)){
titleStr = s.toString().split(">")[1].replaceAll("
java爬虫抓取动态网页(博客系列Java爬虫入门简介(一)——HttpClient请求 )
网站优化 • 优采云 发表了文章 • 0 个评论 • 35 次浏览 • 2022-01-30 02:07
)
博客系列
Java爬虫简介(一)——HttpClient请求(本文)
Java爬虫简介(二)——Jsoup解析HTML页面(本文)
在上一篇博客中,我们已经介绍了如何使用 HttpClient 来模拟客户端请求页面。在本篇博客中,我们将介绍如何解析获取的页面内容。
在上一节中,我们获得了页面的 HTML 源代码,但是这些源代码是提供给浏览器进行解析的。我们需要的数据其实就是页面上博客的标题、作者、简介、发布日期等。我们需要一种方法来从 HTML 源代码中解析这些信息,将其提取出来,并将其存储在文本或数据库中。在本篇博客中,我们将介绍使用 Jsoup 包来帮助我们解析页面和提取数据。
Jsoup是一个Java HTML解析器,可以直接解析一个URL地址或者解析HTML内容。它的主要功能包括解析 HTML 页面、通过 DOM 或 CSS 选择器查找和提取数据以及更改 HTML 内容。Jsoup的使用也很简单。使用Jsoup.parse(String str)方法解析我们之前获取的HTML内容得到一个Document类,剩下的工作就是从Document中选择我们需要的数据。例如,假设我们有一个收录以下内容的 HTML 页面:
第一篇博客
第二篇博客
第三篇博客
通过Jsoup,我们可以将以上三个博客的标题提取成一个List。使用方法如下:
首先,我们通过maven来介绍Jsoup
org.jsoup
jsoup
1.10.3
然后写Java来解析。
package org.hfutec.example;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
public class DataLearnerCrawler {
public static void main(String[] args) {
List titles = new ArrayList();
List urls = new ArrayList();
//假设我们获取的HTML的字符内容如下
String html = "<a href=\"url1\">第一篇博客</a><a href=\"url2\">第二篇博客</a><a href=\"url3\">第三篇博客</a>";
//第一步,将字符内容解析成一个Document类
Document doc = Jsoup.parse(html);
//第二步,根据我们需要得到的标签,选择提取相应标签的内容
Elements elements = doc.select("div[id=blog_list]").select("div[class=blog_title]");
for( Element element : elements ){
String title = element.text();
titles.add(title);
urls.add(element.select("a").attr("href"));
}
//输出测试
for( String title : titles ){
System.out.println(title);
}
for( String url : urls ){
System.out.println(url);
}
}
}
下面简单介绍一下Jsoup的解析过程。第一步是调用parse()方法把字符对象变成Document对象,然后我们对这个对象进行操作。一般来说,提取数据就是根据标签选择数据。select() 方法的语法格式与 javascript/css 选择器的语法格式相同。一般抽取一个标签,其属性值为指定的内容。得到的结果是一个Elements的集合,也就是Elements(因为可能有很多符合条件的标签,所以结果就是一个集合)。select() 方法可以一直持续到我们想要的标签集被选中(注意我们不必从标签层级中逐层选择,我们可以直接将 select() 方法写到我们需要的标签中,例如, 这里的示例代码可以直接写成 Elements elements = doc.select("div[class=blog_title]"); 效果是一样的)。对于选定的一组元素,我们可以通过循环提取每个所需的数据。例如,如果我们需要获取标签的文本信息,可以使用 text() 方法。如果我们需要获取对应的 HTML 属性信息,可以使用 attr() 方法。我们可以看到上述方法的输出如下:
更多Jsoup解析操作请参考以下内容:
1、
2、
一个实例
让我们继续上一个爬取数据的例子来学习官方的网站博客列表来解释一个例子。我们已经知道可以使用 Jsoup 来解析爬取的 HTML 页面内容。那么我们如何查看我们需要的内容对应的标签呢?以Chrome浏览器为例,我们需要爬取这个页面的博客。首先用Chrome浏览器打开网址,然后右击博客标题,点击“Inspect”,得到HTML页面。如下所示。
图2 右击标题
图3 点击元素父元素侧边的小三角关闭代码查看
图4 确认当前博客HTML代码的一致性
经过上面的操作,我们已经可以看到所有的博客标题等信息都存放在class=card div中了。所以,我们只需要注意这个标签中的内容是如何组织的,仅此而已。如下图所示,我们需要的信息所属的标签可以通过点击小三角展开得到。
因此,解析博客列表的代码可以写成如下。
package org.hfutec.example;
import org.apache.http.HttpEntity;
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 org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
public class DataLearnerCrawler {
public static void main(String[] args) {
String url = "http://www.datalearner.com/blog_list";
String rawHTML = null;
try {
rawHTML = getHTMLContent(url);
} catch (IOException e) {
e.printStackTrace();
}
//将当前页面转换成Jsoup的Document对象
Document doc = Jsoup.parse(rawHTML);
//获取所有的博客列表集合
Elements blogList = doc.select("div[class=card]");
//针对每个博客内容进行解析,并输出
for( Element element : blogList ){
String title = element.select("h4[class=card-title]").text();
String introduction = element.select("p[class=card-text]").text();
String author = element.select("span[class=fa fa-user]").text();
System.out.println("Title:\t"+title);
System.out.println("introduction:\t"+introduction);
System.out.println("Author:\t"+author);
System.out.println("--------------------------");
}
}
//根据url地址获取对应页面的HTML内容,我们将上一节中的内容打包成了一个方法,方便调用
private static String getHTMLContent( String url ) throws IOException {
//建立一个新的请求客户端
CloseableHttpClient httpClient = HttpClients.createDefault();
//使用HttpGet方式请求网址
HttpGet httpGet = new HttpGet(url);
//获取网址的返回结果
CloseableHttpResponse response = httpClient.execute(httpGet);
//获取返回结果中的实体
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
//关闭HttpEntity流
EntityUtils.consume(entity);
return content;
}
}
最终输出如下图所示:
查看全部
java爬虫抓取动态网页(博客系列Java爬虫入门简介(一)——HttpClient请求
)
博客系列
Java爬虫简介(一)——HttpClient请求(本文)
Java爬虫简介(二)——Jsoup解析HTML页面(本文)
在上一篇博客中,我们已经介绍了如何使用 HttpClient 来模拟客户端请求页面。在本篇博客中,我们将介绍如何解析获取的页面内容。
在上一节中,我们获得了页面的 HTML 源代码,但是这些源代码是提供给浏览器进行解析的。我们需要的数据其实就是页面上博客的标题、作者、简介、发布日期等。我们需要一种方法来从 HTML 源代码中解析这些信息,将其提取出来,并将其存储在文本或数据库中。在本篇博客中,我们将介绍使用 Jsoup 包来帮助我们解析页面和提取数据。
Jsoup是一个Java HTML解析器,可以直接解析一个URL地址或者解析HTML内容。它的主要功能包括解析 HTML 页面、通过 DOM 或 CSS 选择器查找和提取数据以及更改 HTML 内容。Jsoup的使用也很简单。使用Jsoup.parse(String str)方法解析我们之前获取的HTML内容得到一个Document类,剩下的工作就是从Document中选择我们需要的数据。例如,假设我们有一个收录以下内容的 HTML 页面:
第一篇博客
第二篇博客
第三篇博客
通过Jsoup,我们可以将以上三个博客的标题提取成一个List。使用方法如下:
首先,我们通过maven来介绍Jsoup
org.jsoup
jsoup
1.10.3
然后写Java来解析。
package org.hfutec.example;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
public class DataLearnerCrawler {
public static void main(String[] args) {
List titles = new ArrayList();
List urls = new ArrayList();
//假设我们获取的HTML的字符内容如下
String html = "<a href=\"url1\">第一篇博客</a><a href=\"url2\">第二篇博客</a><a href=\"url3\">第三篇博客</a>";
//第一步,将字符内容解析成一个Document类
Document doc = Jsoup.parse(html);
//第二步,根据我们需要得到的标签,选择提取相应标签的内容
Elements elements = doc.select("div[id=blog_list]").select("div[class=blog_title]");
for( Element element : elements ){
String title = element.text();
titles.add(title);
urls.add(element.select("a").attr("href"));
}
//输出测试
for( String title : titles ){
System.out.println(title);
}
for( String url : urls ){
System.out.println(url);
}
}
}
下面简单介绍一下Jsoup的解析过程。第一步是调用parse()方法把字符对象变成Document对象,然后我们对这个对象进行操作。一般来说,提取数据就是根据标签选择数据。select() 方法的语法格式与 javascript/css 选择器的语法格式相同。一般抽取一个标签,其属性值为指定的内容。得到的结果是一个Elements的集合,也就是Elements(因为可能有很多符合条件的标签,所以结果就是一个集合)。select() 方法可以一直持续到我们想要的标签集被选中(注意我们不必从标签层级中逐层选择,我们可以直接将 select() 方法写到我们需要的标签中,例如, 这里的示例代码可以直接写成 Elements elements = doc.select("div[class=blog_title]"); 效果是一样的)。对于选定的一组元素,我们可以通过循环提取每个所需的数据。例如,如果我们需要获取标签的文本信息,可以使用 text() 方法。如果我们需要获取对应的 HTML 属性信息,可以使用 attr() 方法。我们可以看到上述方法的输出如下:

更多Jsoup解析操作请参考以下内容:
1、
2、
一个实例
让我们继续上一个爬取数据的例子来学习官方的网站博客列表来解释一个例子。我们已经知道可以使用 Jsoup 来解析爬取的 HTML 页面内容。那么我们如何查看我们需要的内容对应的标签呢?以Chrome浏览器为例,我们需要爬取这个页面的博客。首先用Chrome浏览器打开网址,然后右击博客标题,点击“Inspect”,得到HTML页面。如下所示。

图2 右击标题

图3 点击元素父元素侧边的小三角关闭代码查看

图4 确认当前博客HTML代码的一致性
经过上面的操作,我们已经可以看到所有的博客标题等信息都存放在class=card div中了。所以,我们只需要注意这个标签中的内容是如何组织的,仅此而已。如下图所示,我们需要的信息所属的标签可以通过点击小三角展开得到。

因此,解析博客列表的代码可以写成如下。
package org.hfutec.example;
import org.apache.http.HttpEntity;
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 org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
public class DataLearnerCrawler {
public static void main(String[] args) {
String url = "http://www.datalearner.com/blog_list";
String rawHTML = null;
try {
rawHTML = getHTMLContent(url);
} catch (IOException e) {
e.printStackTrace();
}
//将当前页面转换成Jsoup的Document对象
Document doc = Jsoup.parse(rawHTML);
//获取所有的博客列表集合
Elements blogList = doc.select("div[class=card]");
//针对每个博客内容进行解析,并输出
for( Element element : blogList ){
String title = element.select("h4[class=card-title]").text();
String introduction = element.select("p[class=card-text]").text();
String author = element.select("span[class=fa fa-user]").text();
System.out.println("Title:\t"+title);
System.out.println("introduction:\t"+introduction);
System.out.println("Author:\t"+author);
System.out.println("--------------------------");
}
}
//根据url地址获取对应页面的HTML内容,我们将上一节中的内容打包成了一个方法,方便调用
private static String getHTMLContent( String url ) throws IOException {
//建立一个新的请求客户端
CloseableHttpClient httpClient = HttpClients.createDefault();
//使用HttpGet方式请求网址
HttpGet httpGet = new HttpGet(url);
//获取网址的返回结果
CloseableHttpResponse response = httpClient.execute(httpGet);
//获取返回结果中的实体
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
//关闭HttpEntity流
EntityUtils.consume(entity);
return content;
}
}
最终输出如下图所示:

java爬虫抓取动态网页(爬虫Python入门学习分三个阶段的几种方法和方法)
网站优化 • 优采云 发表了文章 • 0 个评论 • 50 次浏览 • 2022-01-23 21:21
学习爬虫 Python 入门容易吗?学习爬虫需要一定的基础,有编程基础的Python爬虫比较容易学习。但是你要多看多练,要有自己的逻辑思路。使用 Python 来实现自己的学习目的是值得的。如果是入门学习和理解,开始学习不难,但是很难深入学习,尤其是大型项目。
大多数爬虫遵循“发送请求-获取页面-解析页面-提取和存储内容”的过程,模拟使用浏览器获取网页信息的过程。向服务器发送请求后,我们会得到返回的页面。解析完页面后,我们就可以提取出我们想要的部分信息,存储到指定的文档或数据库中。爬虫Python入门学习分为三个阶段:
一、零基础阶段:
从零开始学爬虫,上手系统,从0开始爬虫。除了必要的理论知识,爬虫对于实际应用更重要。带你抓取4种主流网站数据,掌握主流爬虫爬取方法。
捕捉主流网站数据的能力是本阶段的学习目标
学习点:爬虫所需的计算机网络/前端/正则//xpath/CSS选择器基础知识;实现静态网页和动态网页两种主流网页类型的数据抓取;模拟登录、响应反爬、识别验证码等,难点详解;多线程、多进程等常见应用场景讲解
二、主流框架
主流框架Scrapy,实现海量数据抓取,提升从原生爬虫到框架的能力。学习后,可以彻底玩转Scrapy框架,开发属于自己的分布式爬虫系统,完全胜任Python中级工程师的工作。获得高效捕获大量数据的能力。
学习点:Scrapy框架知识讲解spider/FormRequest/CrawlSpider等;从单机爬虫到分布式爬虫系统;Scrapy突破了反爬虫的限制和Scrapy的原理;Scrapy 更高级的功能包括 sscrapy 信号、自定义中间件;一些海量数据结合Elasticsearch打造搜索引擎
三、爬虫
深度App数据抓取,爬虫能力提升,处理App数据抓取和数据可视化的能力不再局限于网络爬虫。从现在开始,拓展您的爬虫业务,提升您的核心竞争力。掌握App数据抓取,实现数据可视化
学习重点:学习主流抓包工具Fiddler/Mitmproxy的应用;4种App数据抓取实战,结合学习实践深入掌握App爬虫技巧;基于Docker构建多任务捕获系统,提高工作效率;掌握Pyecharts库基础,绘制基础图形、地图等进行数据可视化。
爬虫 Python 应用在很多领域,比如爬取数据、进行市场调研和商业分析;作为机器学习和数据挖掘的原创数据;爬取优质资源:图片、文字、视频。很容易掌握正确的方法,能够在短时间内爬取主流的网站数据。建议从爬虫 Python 入口开始就设置一个特定的目标。在目标的驱动下,学习会更有效率。 查看全部
java爬虫抓取动态网页(爬虫Python入门学习分三个阶段的几种方法和方法)
学习爬虫 Python 入门容易吗?学习爬虫需要一定的基础,有编程基础的Python爬虫比较容易学习。但是你要多看多练,要有自己的逻辑思路。使用 Python 来实现自己的学习目的是值得的。如果是入门学习和理解,开始学习不难,但是很难深入学习,尤其是大型项目。

大多数爬虫遵循“发送请求-获取页面-解析页面-提取和存储内容”的过程,模拟使用浏览器获取网页信息的过程。向服务器发送请求后,我们会得到返回的页面。解析完页面后,我们就可以提取出我们想要的部分信息,存储到指定的文档或数据库中。爬虫Python入门学习分为三个阶段:
一、零基础阶段:
从零开始学爬虫,上手系统,从0开始爬虫。除了必要的理论知识,爬虫对于实际应用更重要。带你抓取4种主流网站数据,掌握主流爬虫爬取方法。
捕捉主流网站数据的能力是本阶段的学习目标
学习点:爬虫所需的计算机网络/前端/正则//xpath/CSS选择器基础知识;实现静态网页和动态网页两种主流网页类型的数据抓取;模拟登录、响应反爬、识别验证码等,难点详解;多线程、多进程等常见应用场景讲解
二、主流框架
主流框架Scrapy,实现海量数据抓取,提升从原生爬虫到框架的能力。学习后,可以彻底玩转Scrapy框架,开发属于自己的分布式爬虫系统,完全胜任Python中级工程师的工作。获得高效捕获大量数据的能力。
学习点:Scrapy框架知识讲解spider/FormRequest/CrawlSpider等;从单机爬虫到分布式爬虫系统;Scrapy突破了反爬虫的限制和Scrapy的原理;Scrapy 更高级的功能包括 sscrapy 信号、自定义中间件;一些海量数据结合Elasticsearch打造搜索引擎
三、爬虫
深度App数据抓取,爬虫能力提升,处理App数据抓取和数据可视化的能力不再局限于网络爬虫。从现在开始,拓展您的爬虫业务,提升您的核心竞争力。掌握App数据抓取,实现数据可视化
学习重点:学习主流抓包工具Fiddler/Mitmproxy的应用;4种App数据抓取实战,结合学习实践深入掌握App爬虫技巧;基于Docker构建多任务捕获系统,提高工作效率;掌握Pyecharts库基础,绘制基础图形、地图等进行数据可视化。
爬虫 Python 应用在很多领域,比如爬取数据、进行市场调研和商业分析;作为机器学习和数据挖掘的原创数据;爬取优质资源:图片、文字、视频。很容易掌握正确的方法,能够在短时间内爬取主流的网站数据。建议从爬虫 Python 入口开始就设置一个特定的目标。在目标的驱动下,学习会更有效率。
java爬虫抓取动态网页(优雅的使用WebMagic框架,爬取、PhantomJS、Selenium、JavaScriptEngine)
网站优化 • 优采云 发表了文章 • 0 个评论 • 62 次浏览 • 2022-01-23 02:07
优雅使用WebMagic框架爬取唐诗笔苑诗人诗歌数据
同时在几种动态加载技术(HtmlUnit、PhantomJS、Selenium、JavaScriptEngine)中进行比较和选择
虽然 WebMagic 已经快两年没有维护了,但它是一个优秀的爬虫框架的实现。源码中有很多参考,尤其是爬虫多线程的控制。另外,由于爬取的页面是非结构化数据,所以数据保存到MongoDB中。技术准备pom.xml文件中的依赖很简单,没有用到Spring系列框架,所以有些地方已经编码实现了Spring提供的功能。项目结构项目说明
根据需要将数据保存到MongoDB数据库中,所以程序运行前必须设置resources/mongodb.properties文件
最好确保 MongoDB 的版本为 4.0 或更高。另外,MongoDB的用户管理比较麻烦。流程大致如下:首先需要创建一个用于存储数据的数据库,比如user_tangpoem,并存储任意数据(集合)使数据库生效,然后创建数据库
admin数据库的root用户,继续创建一个可以读写应用数据库user_tangpoem的用户,然后修改MongoDB配置文件以安全认证模式启动。重启数据库,选择admin数据库(使用admin)
使用db.auth()用刚刚创建的用户(非root用户)登录,返回1表示认证成功,选择user_tangpoem数据库(使用user_tangpoem),输入show 采集s,如果看到数据库时采集是最初创建的,表示用户创建成功。
详见MongoDB4.0.0远程连接和用户名密码认证登录配置——windows
爬虫以多线程方式运行。线程数和线程休眠时间可以在 resources/spider.properties 文件中设置。设置好数据库配置后,直接运行Main.main(),爬虫就会开始爬取。
线程休眠是WebMagic框架源码中每个线程爬取一个url后必须经过的一个过程,但是作者的文档并没有说明这个,请根据实际情况调整动态加载技术的选择1.PhantomJS和硒
WebMagic 的底层很好地使用了 HttpClient 来加载静态页面。对于动态页面,还有两种常用的 PhantomJSDownloader 和 SeleniumDownloader。
浏览器内核模拟浏览器行为的实现。其中,PhantomJS需要指定phantomjs.exe和要爬取的JS文件,seleniumDownloader需要指定chromedriver.exe,需要自己下载对应操作系统的版本。
使用起来并不难,在本项目中不会过多讨论。这里的关键是解释HtmlUnit
2. HtmlUnit
一款开源的Java页面分析工具,阅读完页面后,可以有效的使用HtmlUnit对页面内容进行分析。纯Java实现的模拟浏览器,无需指定外部文件。
虽然它对 JS 的支持还不完善,但总的来说 HtmlUnit 的内存消耗、CPU 消耗和效率都比 PhantomJS 和 Selenium 好,值得使用
本项目使用2.25版本的HtmlUnit,没有JS添加不成功的问题,但是使用2.3x版本会加载失败3. JavaScriptEngine
因为JavaScriptEngine有局限性,最明显的就是不支持jquery的语法,因为jquery使用的是浏览器的内置对象,而JS引擎本身并没有浏览器对象
当然,只要分析了页面的加载逻辑,如果不涉及浏览器对象的使用,或者转换了 JS 逻辑,仍然可以使用 JS 引擎,但是牺牲了通用性。本项目分析后使用JS引擎加载
4. 横向比较
经测试,三者对比如下
PhantomJS使用外部程序,所以JVM无法管理这部分硬件资源,需要打开任务管理器来爬取进程
经过分析,爬取步骤分为4个步骤:
抓取所有诗人的身份。一次调用接口即可获取所有诗人id,返回JSON格式的数据。接口地址为:抓取所有诗人信息。根据上一步的诗人id,逐一爬取对应诗人的详细信息。一共有2529条数据,然后调用接口2529次,返回JSON格式数据。接口地址为:{id} 抓取所有诗歌信息。根据上一步的诗人信息获取所有诗歌id,然后逐个调用接口获取诗歌的详细信息。总共大约有48000条数据,调用接口48000次返回html页面。需要模拟浏览器动态执行JS。接口地址为:{id}由于js是动态执行的,可能会超时,所以最后需要对还没有成功加载的诗歌信息进行处理,从数据库中读取这样的数据,形成url调用接口再次爬取直到所有数据都完成。这类数据约占1%,接口调用约480次。显然,如上所述,使用了广度优先遍历,所以当执行第三步时,数据将存储在数据库中。
优化后使用Java 8的nashorn JS引擎执行JS代码,不需要动态加载JS,所以不会出现4的问题
时间估计
根据爬取过程分析,忽略程序启动时间和调用接口获取诗人id的时间
在开启 8 个线程的并发模式下(使用 HtmlUnit 动态加载):
所需总数:2529 / 8 5 + 48000 (1 + 0.01)/ 8 * 10 ≈ 62596 秒 ≈ 1043 分钟 ≈ 17.4 小时
以上数据是本地测试得到的,配置为win10 8G i5-4210M 4核
优化后,使用JS引擎代替模拟浏览器动态加载JS,获取诗歌信息所需时间由10秒大幅缩短至6秒左右。因此,重新计算时间如下:
2529 / 8 5 + 48000 / 8 6 ≈ 37185 秒 ≈ 620 分钟 ≈ 10.3 小时
绩效评估
使用模拟浏览器动态加载JS时,观察JVM的使用情况,发现诗歌爬取阶段频繁出现Minor GC(新生代GC),大约每10秒一次,如下图所示。
后来发现多线程模拟浏览器加载页面行为非常占用内存(指同时打开8个浏览器加载网页),对象频繁创建和消费频繁。
建议在运行时通过-Xms -Xmx将JVM内存设置得更大,至少1G,然后将新生代的比例设置为更大的值,如-Xms2048M -Xmx2048M -XX:+UseParallelOldGC -XX:NewRatio =1
后来用JS引擎代替模拟浏览器动态加载JS,不仅速度明显提升,内存消耗也大大降低。Minor GC 平均每分钟发生一次,如下图所示。
最后附上GitHub项目地址: 查看全部
java爬虫抓取动态网页(优雅的使用WebMagic框架,爬取、PhantomJS、Selenium、JavaScriptEngine)
优雅使用WebMagic框架爬取唐诗笔苑诗人诗歌数据
同时在几种动态加载技术(HtmlUnit、PhantomJS、Selenium、JavaScriptEngine)中进行比较和选择
虽然 WebMagic 已经快两年没有维护了,但它是一个优秀的爬虫框架的实现。源码中有很多参考,尤其是爬虫多线程的控制。另外,由于爬取的页面是非结构化数据,所以数据保存到MongoDB中。技术准备pom.xml文件中的依赖很简单,没有用到Spring系列框架,所以有些地方已经编码实现了Spring提供的功能。项目结构项目说明
根据需要将数据保存到MongoDB数据库中,所以程序运行前必须设置resources/mongodb.properties文件
最好确保 MongoDB 的版本为 4.0 或更高。另外,MongoDB的用户管理比较麻烦。流程大致如下:首先需要创建一个用于存储数据的数据库,比如user_tangpoem,并存储任意数据(集合)使数据库生效,然后创建数据库
admin数据库的root用户,继续创建一个可以读写应用数据库user_tangpoem的用户,然后修改MongoDB配置文件以安全认证模式启动。重启数据库,选择admin数据库(使用admin)
使用db.auth()用刚刚创建的用户(非root用户)登录,返回1表示认证成功,选择user_tangpoem数据库(使用user_tangpoem),输入show 采集s,如果看到数据库时采集是最初创建的,表示用户创建成功。
详见MongoDB4.0.0远程连接和用户名密码认证登录配置——windows
爬虫以多线程方式运行。线程数和线程休眠时间可以在 resources/spider.properties 文件中设置。设置好数据库配置后,直接运行Main.main(),爬虫就会开始爬取。
线程休眠是WebMagic框架源码中每个线程爬取一个url后必须经过的一个过程,但是作者的文档并没有说明这个,请根据实际情况调整动态加载技术的选择1.PhantomJS和硒
WebMagic 的底层很好地使用了 HttpClient 来加载静态页面。对于动态页面,还有两种常用的 PhantomJSDownloader 和 SeleniumDownloader。
浏览器内核模拟浏览器行为的实现。其中,PhantomJS需要指定phantomjs.exe和要爬取的JS文件,seleniumDownloader需要指定chromedriver.exe,需要自己下载对应操作系统的版本。
使用起来并不难,在本项目中不会过多讨论。这里的关键是解释HtmlUnit
2. HtmlUnit
一款开源的Java页面分析工具,阅读完页面后,可以有效的使用HtmlUnit对页面内容进行分析。纯Java实现的模拟浏览器,无需指定外部文件。
虽然它对 JS 的支持还不完善,但总的来说 HtmlUnit 的内存消耗、CPU 消耗和效率都比 PhantomJS 和 Selenium 好,值得使用
本项目使用2.25版本的HtmlUnit,没有JS添加不成功的问题,但是使用2.3x版本会加载失败3. JavaScriptEngine
因为JavaScriptEngine有局限性,最明显的就是不支持jquery的语法,因为jquery使用的是浏览器的内置对象,而JS引擎本身并没有浏览器对象
当然,只要分析了页面的加载逻辑,如果不涉及浏览器对象的使用,或者转换了 JS 逻辑,仍然可以使用 JS 引擎,但是牺牲了通用性。本项目分析后使用JS引擎加载
4. 横向比较
经测试,三者对比如下
PhantomJS使用外部程序,所以JVM无法管理这部分硬件资源,需要打开任务管理器来爬取进程
经过分析,爬取步骤分为4个步骤:
抓取所有诗人的身份。一次调用接口即可获取所有诗人id,返回JSON格式的数据。接口地址为:抓取所有诗人信息。根据上一步的诗人id,逐一爬取对应诗人的详细信息。一共有2529条数据,然后调用接口2529次,返回JSON格式数据。接口地址为:{id} 抓取所有诗歌信息。根据上一步的诗人信息获取所有诗歌id,然后逐个调用接口获取诗歌的详细信息。总共大约有48000条数据,调用接口48000次返回html页面。需要模拟浏览器动态执行JS。接口地址为:{id}由于js是动态执行的,可能会超时,所以最后需要对还没有成功加载的诗歌信息进行处理,从数据库中读取这样的数据,形成url调用接口再次爬取直到所有数据都完成。这类数据约占1%,接口调用约480次。显然,如上所述,使用了广度优先遍历,所以当执行第三步时,数据将存储在数据库中。
优化后使用Java 8的nashorn JS引擎执行JS代码,不需要动态加载JS,所以不会出现4的问题
时间估计
根据爬取过程分析,忽略程序启动时间和调用接口获取诗人id的时间
在开启 8 个线程的并发模式下(使用 HtmlUnit 动态加载):
所需总数:2529 / 8 5 + 48000 (1 + 0.01)/ 8 * 10 ≈ 62596 秒 ≈ 1043 分钟 ≈ 17.4 小时
以上数据是本地测试得到的,配置为win10 8G i5-4210M 4核
优化后,使用JS引擎代替模拟浏览器动态加载JS,获取诗歌信息所需时间由10秒大幅缩短至6秒左右。因此,重新计算时间如下:
2529 / 8 5 + 48000 / 8 6 ≈ 37185 秒 ≈ 620 分钟 ≈ 10.3 小时
绩效评估
使用模拟浏览器动态加载JS时,观察JVM的使用情况,发现诗歌爬取阶段频繁出现Minor GC(新生代GC),大约每10秒一次,如下图所示。
后来发现多线程模拟浏览器加载页面行为非常占用内存(指同时打开8个浏览器加载网页),对象频繁创建和消费频繁。
建议在运行时通过-Xms -Xmx将JVM内存设置得更大,至少1G,然后将新生代的比例设置为更大的值,如-Xms2048M -Xmx2048M -XX:+UseParallelOldGC -XX:NewRatio =1
后来用JS引擎代替模拟浏览器动态加载JS,不仅速度明显提升,内存消耗也大大降低。Minor GC 平均每分钟发生一次,如下图所示。
最后附上GitHub项目地址:
java爬虫抓取动态网页(java爬虫的大概流程是怎么样的呢?-八维教育)
网站优化 • 优采云 发表了文章 • 0 个评论 • 42 次浏览 • 2022-01-19 12:05
java爬虫抓取动态网页,爬虫可以抓取通过网页抓取的全部内容,但是大多数情况下,爬虫只能抓取部分网页,因为我们的网站首页往往都很小,每个页面都有好几百k,但是部分页面是空白页面,就抓取不到全部内容。所以我们只要获取到了页面上所有的标题、属性、在什么位置,那么我们就能够抓取到整个页面。那么爬虫的大概流程是怎么样的呢?首先要获取到网页首页的伪装数据,伪装数据大概就是网页所有的内容和文本信息以及它们对应的id,这个id不是每个页面都能够获取到的,获取到id后要通过url提取伪装数据,这个url可以在以后的爬虫文章中专门描述。
获取完伪装数据,就可以开始爬取全部网页,爬虫可以抓取的全部网页,还是那句话,网页所有的信息大多数都在首页,但是没有什么特殊的地方,只要首页没有人操作,那么爬虫一般都可以抓取全部内容。当然还可以根据抓取的内容爬取到网页其他页面的页面,爬虫只抓取首页不放过全部内容,在这里,只爬取首页就可以了。爬虫一般爬取的网页,可以统一把它理解为java爬虫一般实现一个爬虫流程就是以下步骤了。
1、获取页面伪装数据。
2、提取页面内容。
3、获取外链。
4、组合parsemap,获取全部内容。
5、保存。
6、定时发送邮件或其他重要指令。pagecut我们先来看看页面伪装数据,让我们把页面伪装数据想象成是一个代码块,代码块的意思就是指某段代码能够获取某段代码内容的地方,页面伪装数据的不同代码块就相当于不同的段代码。比如:代码块1:basic_tag_css代码块2:loadingimg_getter代码块3:roots(存放/border-top-template/basic_tag_css)代码块4:title代码块5:comment_data代码块6:tag_img首先来看看我们可以通过什么样的代码块来获取首页的伪装数据。
如果我们只想抓取页面伪装数据的话,首先要拿到页面伪装数据所在的代码块,把basic_tag_css存入到bytecode的变量中。再把loadingimg_getter存入到bytecode的变量中。再把roots(存放/border-top-template/loading/get_border_top_image)存入到bytecode的变量中。
再把title存入到bytecode的变量中。还有一个办法是通过反编译代码块进行再次提取该页面中的伪装数据,但是由于我们获取首页可能没有代码块所在的内容就没有用处了,所以我们决定放弃这种方法。pagecut再看看我们提取出来的页面内容,要想获取到伪装数据所在的页面的内容,我们要知道页面里所有的文本信息以及它们对应的id。比。 查看全部
java爬虫抓取动态网页(java爬虫的大概流程是怎么样的呢?-八维教育)
java爬虫抓取动态网页,爬虫可以抓取通过网页抓取的全部内容,但是大多数情况下,爬虫只能抓取部分网页,因为我们的网站首页往往都很小,每个页面都有好几百k,但是部分页面是空白页面,就抓取不到全部内容。所以我们只要获取到了页面上所有的标题、属性、在什么位置,那么我们就能够抓取到整个页面。那么爬虫的大概流程是怎么样的呢?首先要获取到网页首页的伪装数据,伪装数据大概就是网页所有的内容和文本信息以及它们对应的id,这个id不是每个页面都能够获取到的,获取到id后要通过url提取伪装数据,这个url可以在以后的爬虫文章中专门描述。
获取完伪装数据,就可以开始爬取全部网页,爬虫可以抓取的全部网页,还是那句话,网页所有的信息大多数都在首页,但是没有什么特殊的地方,只要首页没有人操作,那么爬虫一般都可以抓取全部内容。当然还可以根据抓取的内容爬取到网页其他页面的页面,爬虫只抓取首页不放过全部内容,在这里,只爬取首页就可以了。爬虫一般爬取的网页,可以统一把它理解为java爬虫一般实现一个爬虫流程就是以下步骤了。
1、获取页面伪装数据。
2、提取页面内容。
3、获取外链。
4、组合parsemap,获取全部内容。
5、保存。
6、定时发送邮件或其他重要指令。pagecut我们先来看看页面伪装数据,让我们把页面伪装数据想象成是一个代码块,代码块的意思就是指某段代码能够获取某段代码内容的地方,页面伪装数据的不同代码块就相当于不同的段代码。比如:代码块1:basic_tag_css代码块2:loadingimg_getter代码块3:roots(存放/border-top-template/basic_tag_css)代码块4:title代码块5:comment_data代码块6:tag_img首先来看看我们可以通过什么样的代码块来获取首页的伪装数据。
如果我们只想抓取页面伪装数据的话,首先要拿到页面伪装数据所在的代码块,把basic_tag_css存入到bytecode的变量中。再把loadingimg_getter存入到bytecode的变量中。再把roots(存放/border-top-template/loading/get_border_top_image)存入到bytecode的变量中。
再把title存入到bytecode的变量中。还有一个办法是通过反编译代码块进行再次提取该页面中的伪装数据,但是由于我们获取首页可能没有代码块所在的内容就没有用处了,所以我们决定放弃这种方法。pagecut再看看我们提取出来的页面内容,要想获取到伪装数据所在的页面的内容,我们要知道页面里所有的文本信息以及它们对应的id。比。
java爬虫抓取动态网页(如何java写/实现网络爬虫抓取网页原理即是保存)
网站优化 • 优采云 发表了文章 • 0 个评论 • 64 次浏览 • 2022-01-18 18:10
如何编写/实现网络爬虫以在java中爬取网页
原理是保存cookie数据,登录后保存cookie。以后每次爬取页面,都会在header信息中发送cookie。系统根据 cookie 判断用户。有了cookie,就有了登录状态,后续的访问都是基于这个cookie对应的用户。补充:Java是一种可以编写跨平台应用软件的聪明才智。
如图:抓取选中地点的a标签下的链接,然后在控制台循环打印出url。如何通过Java代码实现对网页数据的指定爬取,我总结了Jsoup.Jar会在以下步骤中用到宝:人老了,才能有安宁芬芳的状态。就像窗前长出的一株花草,窗外的微风和光线,都是云的赐予,自然而有趣。似乎不是一朵花,而是一片云雾缭绕的热闹气氛。
将Jsoup.jar包导入到项目中,开始认真写诗,仔细检查每一个字,因为有你的影子
获取 URL 指定的 URL 或文档指定的正文。我希望我能幸运地留在你身边,而不是被别人取代。
获取网页中超链接的标题和链接
真实分享网络爬虫java实现原理(源码更好),放心;不管真假,我们都要对自己负责。
最近需要实现一个java网络爬虫来动态爬取其他网站热点新闻。分担复杂度的方法是使用java相关的类来模拟浏览器下载网页,然后使用DOM等技术下载网页,从网页中获取你需要的内容。但是,强烈建议您使用 HttpClient 和 HttpParse 框架来轻松实现网络爬取功能。HttpClient框架主要实现从WEB服务器下载网页数据。不幸的是,所有的旅伴都是临时的。终于一个人长大,跟着不同的团队,最后一个人一个人长大。
如何实现一个Java网络爬虫?你不知道我为你辗转反侧哭泣枕头的那些夜晚你从来不在意
网络爬虫是一种自动提取网页的程序。它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成部分。传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL,在抓取网页的过程中不断地从当前页面中提取新的URL并放入队列中。
如何用java代码实现网络爬虫解析
如何在 Java 中实现网络爬虫
有没有人有java网络爬虫抓取图片的源码
大多数网络快照是在网页上带有图像 url 的快照。高级网络抓包支持部分Javascript,其实原理和javascript中抓取html页面,解析拼接图片地址是一样的。
分享java的爬虫代码,最好爬CNKI万方的参考书目。如果有项目,可以帮忙上传。. .
下面介绍知乎爬虫源码及涉及的主要技术点:(1)程序包组织(2)模拟登录(爬虫主要技术点1)@ > 爬取到需要登录的网站数据,模拟登录是必要的一步,而且往往难度很大。知乎爬虫的模拟登录可以是一个很好的案例。 查看全部
java爬虫抓取动态网页(如何java写/实现网络爬虫抓取网页原理即是保存)
如何编写/实现网络爬虫以在java中爬取网页
原理是保存cookie数据,登录后保存cookie。以后每次爬取页面,都会在header信息中发送cookie。系统根据 cookie 判断用户。有了cookie,就有了登录状态,后续的访问都是基于这个cookie对应的用户。补充:Java是一种可以编写跨平台应用软件的聪明才智。
如图:抓取选中地点的a标签下的链接,然后在控制台循环打印出url。如何通过Java代码实现对网页数据的指定爬取,我总结了Jsoup.Jar会在以下步骤中用到宝:人老了,才能有安宁芬芳的状态。就像窗前长出的一株花草,窗外的微风和光线,都是云的赐予,自然而有趣。似乎不是一朵花,而是一片云雾缭绕的热闹气氛。
将Jsoup.jar包导入到项目中,开始认真写诗,仔细检查每一个字,因为有你的影子
获取 URL 指定的 URL 或文档指定的正文。我希望我能幸运地留在你身边,而不是被别人取代。
获取网页中超链接的标题和链接
真实分享网络爬虫java实现原理(源码更好),放心;不管真假,我们都要对自己负责。
最近需要实现一个java网络爬虫来动态爬取其他网站热点新闻。分担复杂度的方法是使用java相关的类来模拟浏览器下载网页,然后使用DOM等技术下载网页,从网页中获取你需要的内容。但是,强烈建议您使用 HttpClient 和 HttpParse 框架来轻松实现网络爬取功能。HttpClient框架主要实现从WEB服务器下载网页数据。不幸的是,所有的旅伴都是临时的。终于一个人长大,跟着不同的团队,最后一个人一个人长大。
如何实现一个Java网络爬虫?你不知道我为你辗转反侧哭泣枕头的那些夜晚你从来不在意
网络爬虫是一种自动提取网页的程序。它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成部分。传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL,在抓取网页的过程中不断地从当前页面中提取新的URL并放入队列中。
如何用java代码实现网络爬虫解析
如何在 Java 中实现网络爬虫
有没有人有java网络爬虫抓取图片的源码
大多数网络快照是在网页上带有图像 url 的快照。高级网络抓包支持部分Javascript,其实原理和javascript中抓取html页面,解析拼接图片地址是一样的。
分享java的爬虫代码,最好爬CNKI万方的参考书目。如果有项目,可以帮忙上传。. .
下面介绍知乎爬虫源码及涉及的主要技术点:(1)程序包组织(2)模拟登录(爬虫主要技术点1)@ > 爬取到需要登录的网站数据,模拟登录是必要的一步,而且往往难度很大。知乎爬虫的模拟登录可以是一个很好的案例。
java爬虫抓取动态网页(使用java语言开发的一款开源的爬虫工具(Heritrix))
网站优化 • 优采云 发表了文章 • 0 个评论 • 163 次浏览 • 2022-01-16 17:16
今天要和大家分享的是一款使用java语言开发的开源爬虫工具----Heritrix。
大家好,我是奋斗中的小强001。今天的内容将推荐一个用java开发的开源爬虫工具(Heritrix),希望对大家有所帮助。
介绍
Heritrix是java开发的开源网络爬虫,用户可以使用它从互联网上爬取想要的资源。它最好的地方在于其良好的扩展性,方便用户实现自己的爬取逻辑。它是 SourceForge 上的开源产品。
它是如何工作的和工作流程
Heritrix的爬取工作主要由两个核心模块完成,一个是core class核心类,另一个是pluggable modules插件模块。
它的核心类是整个爬虫开发包的核心,可以在此基础上进行定制,但核心类不能被覆盖。反之,可以直接更换插件模块,插件模块相当于插件类型。组件,您也可以使用自己实现的逻辑来替换插件模块。这样就可以更好的根据自己的业务需求自定义爬虫的爬取需求。
整个heritrix技术的工作原理和工作流程是由CrawlController下载控制器决定的,它是整个爬虫操作的启动器,控制着一个爬虫爬取的开始和结束,然后边界控制器Frontier负责采集采集url,下载控制器负责从边界控制器获取对应的url,交给对应的线程池处理。组织和处理。
因为heritrix的url爬取工作是由多个线程执行的,每个线程对应一个url,对应的处理器链执行一次。因此,在整个爬取过程中,最重要的是处理器链。让我们看看处理器链如何处理 url 处理。
第一个是预取链。顾名思义,预取链就是在处理url之前提前准备一些先决条件。
提取链就是将url对应的网页上的所有信息下载整理,然后写入对应的请求响应内容。
提取链:在完成上一步的内容提取后,提取链主要负责提取页面上的a标签,然后提取其他对应的url。
写链主要是把所有的结果组织起来,然后存储起来。
提交链:就是对url做最后的整理工作,然后在采集到的页面上提交其他url,只要把任务范围内的url提交给Frontier,让它做其他的爬取工作。
四、heritrix3安装下载教程1)下载说明
下载heritrix3.x版本的方法还有很多。下面我们推荐几种常用的下载方式:
1、首先推荐heritrix官网直接下载最新版本,因为官网提供的版本是最权威的最新版本,没有bug。它们已经过官方测试,所以它是我们的第一个下载渠道。,但官网地址在国外,有时需要翻墙访问。
2、其次,我们可以直接在GitHub上下载,因为GitHub是源代码下载的权威网站,下载后可以直接使用开发工具直接编译,但是GitHub优先推荐发布版本的儿子。GitHub仓库地址:
2)环境说明
Heritrix对环境依赖有版本要求,所以需要在环境配置的上下文中进行说明。本文文章及以下应用均基于heritrix3.2的版本,该版本所依赖的Java环境JDK为1.7。目前,3.2 版本似乎不支持 jdk1.8。如果将来支持它,我们也会这样做。详细说明和备注。
五、在Linux系统上配置环境变量
按照上面截图的步骤,首先需要配置JDK的环境变量。一般来说,学习爬虫的同学应该对Java非常熟悉。Java_home的环境变量可以直接按照上图的步骤进行配置。故意重复。
第三,heritrix启动和执行都需要权限才能正常启动,所以需要按照上图中的命令配置执行权限。
第三,heritrix启动和执行都需要权限才能正常启动,所以需要按照上图中的命令配置执行权限。
六、启动并运行
由于我们的下载、安装和环境变量配置操作都是在Linux系统上完成的,所以我们在启动heritrix的时候,也需要从命令行启动它。下图显示了我们的启动命令方法和控制台的详细信息。,heritrix登录的默认登录名和密码为admin。
以上步骤完成后,说明heritrix已经正常启动,我们可以在浏览器中访问heritrix的web界面了。默认访问地址为:localhost:8443,即web界面的访问地址。需要注意的是,浏览器的请求方式必须是HTTPS访问。
今天的内容就分享到这里,欢迎大家点赞关注!谢谢! 查看全部
java爬虫抓取动态网页(使用java语言开发的一款开源的爬虫工具(Heritrix))
今天要和大家分享的是一款使用java语言开发的开源爬虫工具----Heritrix。
大家好,我是奋斗中的小强001。今天的内容将推荐一个用java开发的开源爬虫工具(Heritrix),希望对大家有所帮助。
介绍
Heritrix是java开发的开源网络爬虫,用户可以使用它从互联网上爬取想要的资源。它最好的地方在于其良好的扩展性,方便用户实现自己的爬取逻辑。它是 SourceForge 上的开源产品。
它是如何工作的和工作流程
Heritrix的爬取工作主要由两个核心模块完成,一个是core class核心类,另一个是pluggable modules插件模块。
它的核心类是整个爬虫开发包的核心,可以在此基础上进行定制,但核心类不能被覆盖。反之,可以直接更换插件模块,插件模块相当于插件类型。组件,您也可以使用自己实现的逻辑来替换插件模块。这样就可以更好的根据自己的业务需求自定义爬虫的爬取需求。
整个heritrix技术的工作原理和工作流程是由CrawlController下载控制器决定的,它是整个爬虫操作的启动器,控制着一个爬虫爬取的开始和结束,然后边界控制器Frontier负责采集采集url,下载控制器负责从边界控制器获取对应的url,交给对应的线程池处理。组织和处理。
因为heritrix的url爬取工作是由多个线程执行的,每个线程对应一个url,对应的处理器链执行一次。因此,在整个爬取过程中,最重要的是处理器链。让我们看看处理器链如何处理 url 处理。
第一个是预取链。顾名思义,预取链就是在处理url之前提前准备一些先决条件。
提取链就是将url对应的网页上的所有信息下载整理,然后写入对应的请求响应内容。
提取链:在完成上一步的内容提取后,提取链主要负责提取页面上的a标签,然后提取其他对应的url。
写链主要是把所有的结果组织起来,然后存储起来。
提交链:就是对url做最后的整理工作,然后在采集到的页面上提交其他url,只要把任务范围内的url提交给Frontier,让它做其他的爬取工作。
四、heritrix3安装下载教程1)下载说明
下载heritrix3.x版本的方法还有很多。下面我们推荐几种常用的下载方式:
1、首先推荐heritrix官网直接下载最新版本,因为官网提供的版本是最权威的最新版本,没有bug。它们已经过官方测试,所以它是我们的第一个下载渠道。,但官网地址在国外,有时需要翻墙访问。
2、其次,我们可以直接在GitHub上下载,因为GitHub是源代码下载的权威网站,下载后可以直接使用开发工具直接编译,但是GitHub优先推荐发布版本的儿子。GitHub仓库地址:
2)环境说明
Heritrix对环境依赖有版本要求,所以需要在环境配置的上下文中进行说明。本文文章及以下应用均基于heritrix3.2的版本,该版本所依赖的Java环境JDK为1.7。目前,3.2 版本似乎不支持 jdk1.8。如果将来支持它,我们也会这样做。详细说明和备注。
五、在Linux系统上配置环境变量
按照上面截图的步骤,首先需要配置JDK的环境变量。一般来说,学习爬虫的同学应该对Java非常熟悉。Java_home的环境变量可以直接按照上图的步骤进行配置。故意重复。
第三,heritrix启动和执行都需要权限才能正常启动,所以需要按照上图中的命令配置执行权限。
第三,heritrix启动和执行都需要权限才能正常启动,所以需要按照上图中的命令配置执行权限。
六、启动并运行
由于我们的下载、安装和环境变量配置操作都是在Linux系统上完成的,所以我们在启动heritrix的时候,也需要从命令行启动它。下图显示了我们的启动命令方法和控制台的详细信息。,heritrix登录的默认登录名和密码为admin。
以上步骤完成后,说明heritrix已经正常启动,我们可以在浏览器中访问heritrix的web界面了。默认访问地址为:localhost:8443,即web界面的访问地址。需要注意的是,浏览器的请求方式必须是HTTPS访问。
今天的内容就分享到这里,欢迎大家点赞关注!谢谢!
java爬虫抓取动态网页( WebMagic使用slf4j-log4j12测试方法 )
网站优化 • 优采云 发表了文章 • 0 个评论 • 65 次浏览 • 2022-01-16 08:14
WebMagic使用slf4j-log4j12测试方法
)
<p>WebMagic的架构设计参照了Scrapy,而实现则应用了HttpClient、Jsoup等Java成熟的工具。<br /> <br /> WebMagic由四个组件(Downloader、PageProcessor、Scheduler、Pipeline)构成:
Downloader : 下载器PageProcessor: 页面解析器Scheduler: 任务分配、url去重Pipeline:数据存储、处理
WebMagic数据流转的对象:
Request : 一个Request对应一个URL地址 。它是是PageProcessor控制Downloader唯一方式。Page : 代表了从Downloader下载到的内容ResultItems : 相当于一个Map,它保存PageProcessor处理的结果,供Pipeline使用。
爬虫引擎–Spider:
Spider是WebMagic内部流程的核心,上面的四个组件都相当于Spider的一个属性,通过设置这个属性可以实现不同的功能。Spider也是WebMagic操作的入口,它封装了爬虫的创建、启动、停止、多线程等功能
<a id="_MavenWebMagic_26"></a>使用 Maven来安装WebMagic
us.codecraft
webmagic-core
0.7.3
us.codecraft
webmagic-extension
0.7.3
</p>
WebMagic 使用 slf4j-log4j12 作为 slf4j 的实现。如果自己自定义slf4j的实现,需要从项目中去掉这个依赖。
us.codecraft
webmagic-extension
0.7.3
org.slf4j
slf4j-log4j12
如果你不使用Maven,可以去下载最新的jar包,下载后解压,然后导入到项目中。
开始开发第一个爬虫
在项目中添加WebMagic的依赖后,就可以开始第一个爬虫的开发了!
下面是一个测试,点击main方法,选择“运行”看看是否正常运行。
package com.example.demo;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
public class DemoPageGet implements PageProcessor {
private Site site = Site.me();
@Override
public void process(Page page) {
System.out.println(page.getHtml());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new DemoPageGet()).addUrl("http://httpbin.org/get").run();
}
}
编写一个基本的爬虫
在WebMagic中,实现一个基本的爬虫只需要写一个实现PageProcessor接口的类。
这一部分我们通过GithubRepoPageProcessor的例子直接介绍PageProcessor的编写方式。
PageProcessor的定制分为爬虫配置、页面元素提取和链接发现三个部分。
public class GithubRepoPageProcessor implements PageProcessor {
// 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
@Override
// process是定制爬虫逻辑的核心接口,在这里编写抽取逻辑
public void process(Page page) {
// 部分二:定义如何抽取页面信息,并保存下来
page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());
page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString());
if (page.getResultItems().get("name") == null) {
//skip this page
page.setSkip(true);
}
page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));
// 部分三:从页面发现后续的url地址来抓取
page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/[\\w\\-]+/[\\w\\-]+)").all());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从"https://github.com/code4craft"开始抓
.addUrl("https://github.com/code4craft")
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
}
附加请求的链接
首先,通过正则表达式匹配或拼接出链接,例如:page.getHtml().links().regex("").all()
通过 addTargetRequests 方法 page.addTargetRequests(url) 将这些链接添加到要爬取的队列中。
爬虫的配置
Spider:爬虫程序的入口,可以通过set方法设置Spider的其他组件(Downloader、Scheduler、Pipeline)。
Site:站点本身的一些配置信息,如编码、HTTP头、超时、重试策略等,代理等,可以通过设置Site对象来配置。
配置 http 代理。从版本0.7.1开始,WebMagic开始使用新的代理APIProxyProvider,因为ProxyProvider定位更像是一个“组件”而不是Site的“配置”,所以代理不再从站点设置,但由 HttpClientDownloader 设置。
查看官方文档了解更多详情。
页面元素的提取
WebMagic 中使用了三种主要的数据提取技术:
使用管道保存结果
WebMagic 用来保存结果的组件称为管道。
比如我们通过“控制台输出”做的事情,也是通过一个内置的Pipeline来完成的,这个Pipeline叫做ConsolePipeline。
那么,我现在想把结果保存成Json格式,怎么做呢?
我只需要将 Pipeline 的实现替换为“JsonFilePipeline”即可。
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从"https://github.com/code4craft"开始抓
.addUrl("https://github.com/code4craft")
.addPipeline(new JsonFilePipeline("./webmagic"))
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
模拟 POST 请求方法
0.7.1版以后放弃了nameValuePair的老写法,通过在Request对象中添加Method和requestBody来实现。
Request request = new Request("http://xxx/path");
request.setMethod(HttpConstant.Method.POST);
request.setRequestBody(HttpRequestBody.json("{'id':1}","utf-8"));
HttpRequestBody内置多种初始化方法,支持最常见的表单提交、json提交等方法。
查看全部
java爬虫抓取动态网页(
WebMagic使用slf4j-log4j12测试方法
)
<p>WebMagic的架构设计参照了Scrapy,而实现则应用了HttpClient、Jsoup等Java成熟的工具。<br />

Downloader : 下载器PageProcessor: 页面解析器Scheduler: 任务分配、url去重Pipeline:数据存储、处理
WebMagic数据流转的对象:
Request : 一个Request对应一个URL地址 。它是是PageProcessor控制Downloader唯一方式。Page : 代表了从Downloader下载到的内容ResultItems : 相当于一个Map,它保存PageProcessor处理的结果,供Pipeline使用。
爬虫引擎–Spider:
Spider是WebMagic内部流程的核心,上面的四个组件都相当于Spider的一个属性,通过设置这个属性可以实现不同的功能。Spider也是WebMagic操作的入口,它封装了爬虫的创建、启动、停止、多线程等功能
<a id="_MavenWebMagic_26"></a>使用 Maven来安装WebMagic
us.codecraft
webmagic-core
0.7.3
us.codecraft
webmagic-extension
0.7.3
</p>

WebMagic 使用 slf4j-log4j12 作为 slf4j 的实现。如果自己自定义slf4j的实现,需要从项目中去掉这个依赖。
us.codecraft
webmagic-extension
0.7.3
org.slf4j
slf4j-log4j12
如果你不使用Maven,可以去下载最新的jar包,下载后解压,然后导入到项目中。
开始开发第一个爬虫
在项目中添加WebMagic的依赖后,就可以开始第一个爬虫的开发了!
下面是一个测试,点击main方法,选择“运行”看看是否正常运行。
package com.example.demo;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
public class DemoPageGet implements PageProcessor {
private Site site = Site.me();
@Override
public void process(Page page) {
System.out.println(page.getHtml());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new DemoPageGet()).addUrl("http://httpbin.org/get").run();
}
}
编写一个基本的爬虫
在WebMagic中,实现一个基本的爬虫只需要写一个实现PageProcessor接口的类。
这一部分我们通过GithubRepoPageProcessor的例子直接介绍PageProcessor的编写方式。
PageProcessor的定制分为爬虫配置、页面元素提取和链接发现三个部分。
public class GithubRepoPageProcessor implements PageProcessor {
// 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
@Override
// process是定制爬虫逻辑的核心接口,在这里编写抽取逻辑
public void process(Page page) {
// 部分二:定义如何抽取页面信息,并保存下来
page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());
page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString());
if (page.getResultItems().get("name") == null) {
//skip this page
page.setSkip(true);
}
page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));
// 部分三:从页面发现后续的url地址来抓取
page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/[\\w\\-]+/[\\w\\-]+)").all());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从"https://github.com/code4craft"开始抓
.addUrl("https://github.com/code4craft")
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
}
附加请求的链接
首先,通过正则表达式匹配或拼接出链接,例如:page.getHtml().links().regex("").all()
通过 addTargetRequests 方法 page.addTargetRequests(url) 将这些链接添加到要爬取的队列中。
爬虫的配置
Spider:爬虫程序的入口,可以通过set方法设置Spider的其他组件(Downloader、Scheduler、Pipeline)。

Site:站点本身的一些配置信息,如编码、HTTP头、超时、重试策略等,代理等,可以通过设置Site对象来配置。

配置 http 代理。从版本0.7.1开始,WebMagic开始使用新的代理APIProxyProvider,因为ProxyProvider定位更像是一个“组件”而不是Site的“配置”,所以代理不再从站点设置,但由 HttpClientDownloader 设置。
查看官方文档了解更多详情。
页面元素的提取
WebMagic 中使用了三种主要的数据提取技术:
使用管道保存结果
WebMagic 用来保存结果的组件称为管道。
比如我们通过“控制台输出”做的事情,也是通过一个内置的Pipeline来完成的,这个Pipeline叫做ConsolePipeline。
那么,我现在想把结果保存成Json格式,怎么做呢?
我只需要将 Pipeline 的实现替换为“JsonFilePipeline”即可。
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从"https://github.com/code4craft"开始抓
.addUrl("https://github.com/code4craft")
.addPipeline(new JsonFilePipeline("./webmagic"))
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
模拟 POST 请求方法
0.7.1版以后放弃了nameValuePair的老写法,通过在Request对象中添加Method和requestBody来实现。
Request request = new Request("http://xxx/path");
request.setMethod(HttpConstant.Method.POST);
request.setRequestBody(HttpRequestBody.json("{'id':1}","utf-8"));
HttpRequestBody内置多种初始化方法,支持最常见的表单提交、json提交等方法。

java爬虫抓取动态网页(python如何检测网页中是否存在动态加载的数据?(图))
网站优化 • 优采云 发表了文章 • 0 个评论 • 49 次浏览 • 2022-01-15 23:10
在使用python爬虫技术采集数据信息时,经常会遇到在返回的网页信息中无法抓取到动态加载的可用数据。例如,当在网页中获取产品的价格时,就会出现这种现象。如下所示。本文将实现类似的动态加载数据爬取网页。
1. 那么什么是动态加载的数据呢?
我们通过requests模块爬取的数据不能每次都是可见的,部分数据是通过非浏览器地址栏中的url请求获取的。相反,通过其他请求请求的数据,然后通过其他请求请求的数据是动态加载的数据。(猜测是js代码在我们访问这个页面从其他url获取数据的时候会发送get请求)
2. 如何检测网页中是否有动态加载的数据?
在当前页面打开抓包工具,在地址栏抓到url对应的数据包,在数据包的response选项卡中搜索我们要抓取的数据。如果找到了搜索结果,说明数据不是动态加载的。否则,数据将被动态加载。如图所示:
或者右键要爬取的页面,显示网页的源代码,搜索我们要爬取的数据。如果搜索到结果,说明数据没有动态加载,否则说明数据是动态加载的。如图所示:
3. 如果数据是动态加载的,我们如何捕获动态加载的数据呢?
在实现对动态加载的数据信息的爬取时,首先需要根据动态加载技术在浏览器的网络监控器中选择网络请求的类型,然后对预览信息中的关键数据进行一一过滤查询,得到对应请求地址,最后解析信息。具体步骤如下:
在浏览器中,按快捷键F12打开开发者工具,然后选择Network(网络监视器),在网络类型中选择JS,然后按快捷键F5刷新,如下图。
在请求信息列表中,依次点击各个请求信息,然后在对应的Preview(请求结果预览)中查看是否是需要获取的动态加载的数据,如下图所示。
查看动态加载的数据信息后,点击Headers获取当前网络请求地址和所需参数,如下图所示。
根据上述步骤得到的请求地址,发出网络请求,从返回的信息中提取商品价格信息。作者在代码中使用了反序列化。关于json序列化和反序列化,可以点这里学习。代码如下:
import requests
import json
# 获取商品价格的请求地址
url = "https://c0.3.cn/stock?skuId=12464037&cat=1713,3259,3333&venderId=1000077923&area" \
"=4_113_9786_0&buyNum=1&choseSuitSkuIds=&extraParam={%22originid%22:%221%22}&ch=1&fqsp=0&" \
"pduid=1573698619147398205303&pdpin=jd_635f3b795bb1c&coord=&detailedAdd=&callback=jQuery6495921"
jQuery_id = url.split("=")[-1] + "("
# 头部信息
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
}
# 发送网络请求
response = requests.get(url, headers=headers)
if response.status_code == 200:
goods_dict = json.loads(response.text.replace(jQuery_id, "")[:-1]) # 反序列化
print(f"当前售价为: {goods_dict['stock']['jdPrice']['op']}")
print(f"定价为: {goods_dict['stock']['jdPrice']['m']}")
print(f"会员价为: {goods_dict['stock']['jdPrice']['tpp']}")
else:
print("请求失败!")
作者在写博文的时候,价格发生了变化,运行结果如下图所示:
注意:爬取动态加载的数据信息时,需要根据不同的网页使用不同的方法提取数据。如果运行源码时出现错误,请按照步骤获取新的请求地址。
至此,这篇关于Python实现网页中动态加载数据爬取的文章文章就介绍到这里了。更多关于Python爬取网页动态数据的信息,请搜索我们之前的文章或继续浏览下面的相关文章希望大家以后多多支持! 查看全部
java爬虫抓取动态网页(python如何检测网页中是否存在动态加载的数据?(图))
在使用python爬虫技术采集数据信息时,经常会遇到在返回的网页信息中无法抓取到动态加载的可用数据。例如,当在网页中获取产品的价格时,就会出现这种现象。如下所示。本文将实现类似的动态加载数据爬取网页。

1. 那么什么是动态加载的数据呢?
我们通过requests模块爬取的数据不能每次都是可见的,部分数据是通过非浏览器地址栏中的url请求获取的。相反,通过其他请求请求的数据,然后通过其他请求请求的数据是动态加载的数据。(猜测是js代码在我们访问这个页面从其他url获取数据的时候会发送get请求)
2. 如何检测网页中是否有动态加载的数据?
在当前页面打开抓包工具,在地址栏抓到url对应的数据包,在数据包的response选项卡中搜索我们要抓取的数据。如果找到了搜索结果,说明数据不是动态加载的。否则,数据将被动态加载。如图所示:

或者右键要爬取的页面,显示网页的源代码,搜索我们要爬取的数据。如果搜索到结果,说明数据没有动态加载,否则说明数据是动态加载的。如图所示:

3. 如果数据是动态加载的,我们如何捕获动态加载的数据呢?
在实现对动态加载的数据信息的爬取时,首先需要根据动态加载技术在浏览器的网络监控器中选择网络请求的类型,然后对预览信息中的关键数据进行一一过滤查询,得到对应请求地址,最后解析信息。具体步骤如下:
在浏览器中,按快捷键F12打开开发者工具,然后选择Network(网络监视器),在网络类型中选择JS,然后按快捷键F5刷新,如下图。

在请求信息列表中,依次点击各个请求信息,然后在对应的Preview(请求结果预览)中查看是否是需要获取的动态加载的数据,如下图所示。

查看动态加载的数据信息后,点击Headers获取当前网络请求地址和所需参数,如下图所示。

根据上述步骤得到的请求地址,发出网络请求,从返回的信息中提取商品价格信息。作者在代码中使用了反序列化。关于json序列化和反序列化,可以点这里学习。代码如下:
import requests
import json
# 获取商品价格的请求地址
url = "https://c0.3.cn/stock?skuId=12464037&cat=1713,3259,3333&venderId=1000077923&area" \
"=4_113_9786_0&buyNum=1&choseSuitSkuIds=&extraParam={%22originid%22:%221%22}&ch=1&fqsp=0&" \
"pduid=1573698619147398205303&pdpin=jd_635f3b795bb1c&coord=&detailedAdd=&callback=jQuery6495921"
jQuery_id = url.split("=")[-1] + "("
# 头部信息
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
}
# 发送网络请求
response = requests.get(url, headers=headers)
if response.status_code == 200:
goods_dict = json.loads(response.text.replace(jQuery_id, "")[:-1]) # 反序列化
print(f"当前售价为: {goods_dict['stock']['jdPrice']['op']}")
print(f"定价为: {goods_dict['stock']['jdPrice']['m']}")
print(f"会员价为: {goods_dict['stock']['jdPrice']['tpp']}")
else:
print("请求失败!")
作者在写博文的时候,价格发生了变化,运行结果如下图所示:

注意:爬取动态加载的数据信息时,需要根据不同的网页使用不同的方法提取数据。如果运行源码时出现错误,请按照步骤获取新的请求地址。
至此,这篇关于Python实现网页中动态加载数据爬取的文章文章就介绍到这里了。更多关于Python爬取网页动态数据的信息,请搜索我们之前的文章或继续浏览下面的相关文章希望大家以后多多支持!
java爬虫抓取动态网页(java爬虫抓取动态网页的视频和文档原代码在【利用java实现哔哩视频爬虫】)
网站优化 • 优采云 发表了文章 • 0 个评论 • 52 次浏览 • 2022-01-15 01:01
java爬虫抓取动态网页的视频和文档原代码在【利用java实现哔哩哔哩视频爬虫】
我个人建议是直接用threadpoolexecutor或者futuretask吧,基本框架不用选择httpclient,而是rxjava。
进入mybatis(深入理解spring)-in-1.html,
动态网页采集看楼主的说明,应该是你现在做的jsp页面不是java所能处理的,html和css要优化才能做动态。建议:既然是用springmvc+ejb+jpa来处理网页,
万能插件:threadpoolexecutor。没有它怎么可以说动态的java爬虫。以上是demo,
动态网页很难做,java并不能处理这些网页。
做java网页也还是要在jsp下写呢吧。用ejb或者mybatis吧。
spring+ejb+mybatis,
threadpoolexecutor和jboss动态网页也是可以的。根据题主的要求,应该是需要代理服务器来处理http请求。
看在哪些web应用场景了,代理服务器为proxy-sideproxy,proxy-sideproxy是自动插入路由器的端口映射,然后发起http连接。如果你是要替换为google的服务,需要注意,他们的http接口没有模拟socket,http本身支持异步,一般用c++封装成socket的框架使用,如web框架glassfish-c++插件。
如果替换成其他常用web服务器,如tomcat/iis,建议用,反序列化使用objectsocket(和tcp一样的功能,但是是一次响应),注意是在路由器上处理,不是客户端,服务器端和客户端的通信,双方都是有可能会丢失重复。使用完了就切到自己的内部路由上。以上看下这个,那些场景下可以比较快,你可以在开始学习的时候,分类查找,很重要。 查看全部
java爬虫抓取动态网页(java爬虫抓取动态网页的视频和文档原代码在【利用java实现哔哩视频爬虫】)
java爬虫抓取动态网页的视频和文档原代码在【利用java实现哔哩哔哩视频爬虫】
我个人建议是直接用threadpoolexecutor或者futuretask吧,基本框架不用选择httpclient,而是rxjava。
进入mybatis(深入理解spring)-in-1.html,
动态网页采集看楼主的说明,应该是你现在做的jsp页面不是java所能处理的,html和css要优化才能做动态。建议:既然是用springmvc+ejb+jpa来处理网页,
万能插件:threadpoolexecutor。没有它怎么可以说动态的java爬虫。以上是demo,
动态网页很难做,java并不能处理这些网页。
做java网页也还是要在jsp下写呢吧。用ejb或者mybatis吧。
spring+ejb+mybatis,
threadpoolexecutor和jboss动态网页也是可以的。根据题主的要求,应该是需要代理服务器来处理http请求。
看在哪些web应用场景了,代理服务器为proxy-sideproxy,proxy-sideproxy是自动插入路由器的端口映射,然后发起http连接。如果你是要替换为google的服务,需要注意,他们的http接口没有模拟socket,http本身支持异步,一般用c++封装成socket的框架使用,如web框架glassfish-c++插件。
如果替换成其他常用web服务器,如tomcat/iis,建议用,反序列化使用objectsocket(和tcp一样的功能,但是是一次响应),注意是在路由器上处理,不是客户端,服务器端和客户端的通信,双方都是有可能会丢失重复。使用完了就切到自己的内部路由上。以上看下这个,那些场景下可以比较快,你可以在开始学习的时候,分类查找,很重要。
java爬虫抓取动态网页(一家出数据库表结构下面贴出爬虫的动态代理实现爬虫)
网站优化 • 优采云 发表了文章 • 0 个评论 • 61 次浏览 • 2022-02-09 19:23
作者的公司是一个区块链门户网站,网站的很多信息、新闻、视频等数据都是通过爬取第三方网站获取的,需要获取从很多网站来爬取数据,如果每个数据源网站都需要编写单独的接口来爬取,工作量无疑是巨大的,因为作者想到了通过动态实现一套爬虫机制proxy,每次爬取一个新的数据源,只需要在数据库中添加一个数据源,不需要修改代码。
废话不多说,下面贴出数据库表结构
DROP TABLE IF EXISTS `yiyi_crawler_website`;
CREATE TABLE `yiyi_crawler_website` (
`id` bigint(16) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`url` varchar(255) DEFAULT NULL COMMENT '网站链接(抓取内容的接口)',
`interval` bigint(16) DEFAULT '0' COMMENT '抓取时间间隔(以毫秒为单位)',
`website_type` tinyint(20) DEFAULT NULL COMMENT '网站类型(1、快讯)',
`website_name` varchar(32) DEFAULT NULL COMMENT '网站名',
`source_link` varchar(255) DEFAULT NULL COMMENT '来源链接',
`data_field` varchar(32) DEFAULT NULL COMMENT '数据所在字段,如果没有,为空则直接取数(多级以.连接,如果:data.items表示data下面的items为内容列表)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `yiyi_crawler_website_content`;
CREATE TABLE `yiyi_crawler_website_content` (
`id` bigint(16) NOT NULL AUTO_INCREMENT,
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`website_id` bigint(16) DEFAULT NULL COMMENT '网站ID',
`content_name` varchar(16) DEFAULT NULL COMMENT '内容名',
`table_name` varchar(32) DEFAULT NULL COMMENT '所属表名',
`column_name` varchar(32) DEFAULT NULL COMMENT '所属字段名',
`return_field` varchar(32) DEFAULT NULL COMMENT '当前要抓取的字段所返回的字段',
`field_type` tinyint(2) DEFAULT '2' COMMENT '字段类型(1、日期2、数值0、其他)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
下面贴出爬虫的动态代理实现,基于cglib框架。
/**
* 爬虫任务代理接口
*
* @author liyi
* @create 2018-03-17 16:58
**/
public interface CrawlerProxy {
/**
* 任务开始
* @param website
*/
void start(CrawlerWebsiteModelOut website);
}
/**
* 爬虫任务类
*
* @author liyi
* @create 2018-03-17 18:21
**/
public class CrawlerTask implements CrawlerProxy {
@Override
public void start(CrawlerWebsiteModelOut website) {
System.out.println("爬虫任务开始");
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import java.util.*;
/**
* 爬虫定时任务
*
* @author liyi
* @create 2018-03-17 18:35
**/
public class CrawlerTimerTask extends TimerTask {
private CrawlerWebsiteModelOut website = null;
@Override
public void run() {
String json = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
String strs[] = website.getDataField().split(".");
List dataList = new ArrayList();
Arrays.stream(strs).forEach(s -> {
dataList.clear();
String data = JSON.parseObject(json, new TypeReference() {}.getType());
dataList.add(data);
});
}
public void setWebsite(CrawlerWebsiteModelOut website) {
this.website = website;
}
public CrawlerWebsiteModelOut getWebsite() {
return website;
}
}
import com.alibaba.fastjson.JSONObject;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import com.lynn.yiyi.service.CrawlerService;
import com.lynn.yiyi.utils.SpringUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 爬虫动态代理类
*
* @author liyi
* @create 2018-03-17 18:22
**/
public class CrawlerCglibProxy implements MethodInterceptor {
private Map timerMap = new HashMap();
private Enhancer enhancer = new Enhancer();
Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object o = proxy.invokeSuper(obj,args);
if("start".equals(method.getName())){
if(args[0] instanceof CrawlerWebsiteModelOut){
CrawlerWebsiteModelOut website = (CrawlerWebsiteModelOut)args[0];
if(timerMap.get(website.getId()) == null){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
String data = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
String strs[] = website.getDataField().split("\\.");
for (String s : strs) {
JSONObject object = JSONObject.parseObject(data);
data = object.getString(s);
}
//TODO 这里将爬取到的数据写到数据库对应的表中
}
}, 0, website.getInterval());
timerMap.put(website.getId(),timer);
}
}
}
return o;
}
public static T create(Class cls){
CrawlerCglibProxy proxy = new CrawlerCglibProxy();
return (T)proxy.getProxy(cls);
}
}
import java.util.ArrayList;
import java.util.List;
/**
* 网站爬虫输出参数
*
* @author liyi
* @create 2018-03-17 17:04
**/
public class CrawlerWebsiteModelOut extends BaseModelOut {
private String url;
private Long interval;
private Integer websiteType;
private String websiteName;
private String sourceLink;
private String dataField;
private List contentList = new ArrayList();
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Long getInterval() {
return interval;
}
public void setInterval(Long interval) {
this.interval = interval;
}
public Integer getWebsiteType() {
return websiteType;
}
public void setWebsiteType(Integer websiteType) {
this.websiteType = websiteType;
}
public String getWebsiteName() {
return websiteName;
}
public void setWebsiteName(String websiteName) {
this.websiteName = websiteName;
}
public String getSourceLink() {
return sourceLink;
}
public void setSourceLink(String sourceLink) {
this.sourceLink = sourceLink;
}
public String getDataField() {
return dataField;
}
public void setDataField(String dataField) {
this.dataField = dataField;
}
public List getContentList() {
return contentList;
}
public void setContentList(List contentList) {
this.contentList = contentList;
}
}
/**
* 爬虫网站内容输出参数
*/
public class CrawlerWebsiteContentModelOut extends BaseModelOut{
private Long websiteId;
private String contentName;
private String tableName;
private String columnName;
private String returnField;
private Integer fieldType;
public Long getWebsiteId() {
return websiteId;
}
public void setWebsiteId(Long websiteId) {
this.websiteId = websiteId;
}
public String getContentName() {
return contentName;
}
public void setContentName(String contentName) {
this.contentName = contentName;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getReturnField() {
return returnField;
}
public void setReturnField(String returnField) {
this.returnField = returnField;
}
public Integer getFieldType() {
return fieldType;
}
public void setFieldType(Integer fieldType) {
this.fieldType = fieldType;
}
}
import java.util.Date;
/**
* 基础输出参数
*
* @author liyi
* @create 2018-03-17 17:02
**/
public abstract class BaseModelOut{
private Long id;
private Date create;
private Date modified;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getCreate() {
return create;
}
public void setCreate(Date create) {
this.create = create;
}
public Date getModified() {
return modified;
}
public void setModified(Date modified) {
this.modified = modified;
}
}
下面给出测试的主要方法
public static void main(String[] args) {
CrawlerProxy proxy = CrawlerFactory.create();
proxy.start(website);//website即当前要爬取的网站对象,可以从数据库中读取
}
调用main方法启动定时器,定时从指定网站爬取数据。 查看全部
java爬虫抓取动态网页(一家出数据库表结构下面贴出爬虫的动态代理实现爬虫)
作者的公司是一个区块链门户网站,网站的很多信息、新闻、视频等数据都是通过爬取第三方网站获取的,需要获取从很多网站来爬取数据,如果每个数据源网站都需要编写单独的接口来爬取,工作量无疑是巨大的,因为作者想到了通过动态实现一套爬虫机制proxy,每次爬取一个新的数据源,只需要在数据库中添加一个数据源,不需要修改代码。
废话不多说,下面贴出数据库表结构
DROP TABLE IF EXISTS `yiyi_crawler_website`;
CREATE TABLE `yiyi_crawler_website` (
`id` bigint(16) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`url` varchar(255) DEFAULT NULL COMMENT '网站链接(抓取内容的接口)',
`interval` bigint(16) DEFAULT '0' COMMENT '抓取时间间隔(以毫秒为单位)',
`website_type` tinyint(20) DEFAULT NULL COMMENT '网站类型(1、快讯)',
`website_name` varchar(32) DEFAULT NULL COMMENT '网站名',
`source_link` varchar(255) DEFAULT NULL COMMENT '来源链接',
`data_field` varchar(32) DEFAULT NULL COMMENT '数据所在字段,如果没有,为空则直接取数(多级以.连接,如果:data.items表示data下面的items为内容列表)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `yiyi_crawler_website_content`;
CREATE TABLE `yiyi_crawler_website_content` (
`id` bigint(16) NOT NULL AUTO_INCREMENT,
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`website_id` bigint(16) DEFAULT NULL COMMENT '网站ID',
`content_name` varchar(16) DEFAULT NULL COMMENT '内容名',
`table_name` varchar(32) DEFAULT NULL COMMENT '所属表名',
`column_name` varchar(32) DEFAULT NULL COMMENT '所属字段名',
`return_field` varchar(32) DEFAULT NULL COMMENT '当前要抓取的字段所返回的字段',
`field_type` tinyint(2) DEFAULT '2' COMMENT '字段类型(1、日期2、数值0、其他)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
下面贴出爬虫的动态代理实现,基于cglib框架。
/**
* 爬虫任务代理接口
*
* @author liyi
* @create 2018-03-17 16:58
**/
public interface CrawlerProxy {
/**
* 任务开始
* @param website
*/
void start(CrawlerWebsiteModelOut website);
}
/**
* 爬虫任务类
*
* @author liyi
* @create 2018-03-17 18:21
**/
public class CrawlerTask implements CrawlerProxy {
@Override
public void start(CrawlerWebsiteModelOut website) {
System.out.println("爬虫任务开始");
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import java.util.*;
/**
* 爬虫定时任务
*
* @author liyi
* @create 2018-03-17 18:35
**/
public class CrawlerTimerTask extends TimerTask {
private CrawlerWebsiteModelOut website = null;
@Override
public void run() {
String json = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
String strs[] = website.getDataField().split(".");
List dataList = new ArrayList();
Arrays.stream(strs).forEach(s -> {
dataList.clear();
String data = JSON.parseObject(json, new TypeReference() {}.getType());
dataList.add(data);
});
}
public void setWebsite(CrawlerWebsiteModelOut website) {
this.website = website;
}
public CrawlerWebsiteModelOut getWebsite() {
return website;
}
}
import com.alibaba.fastjson.JSONObject;
import com.lynn.yiyi.http.Request;
import com.lynn.yiyi.http.WebUtils;
import com.lynn.yiyi.model.out.CrawlerWebsiteModelOut;
import com.lynn.yiyi.service.CrawlerService;
import com.lynn.yiyi.utils.SpringUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 爬虫动态代理类
*
* @author liyi
* @create 2018-03-17 18:22
**/
public class CrawlerCglibProxy implements MethodInterceptor {
private Map timerMap = new HashMap();
private Enhancer enhancer = new Enhancer();
Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object o = proxy.invokeSuper(obj,args);
if("start".equals(method.getName())){
if(args[0] instanceof CrawlerWebsiteModelOut){
CrawlerWebsiteModelOut website = (CrawlerWebsiteModelOut)args[0];
if(timerMap.get(website.getId()) == null){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
String data = WebUtils.executeHttp(Request.options().setMethod(com.lynn.yiyi.http.Method.GET).setUrl(website.getUrl()).build()).getJsonString();
String strs[] = website.getDataField().split("\\.");
for (String s : strs) {
JSONObject object = JSONObject.parseObject(data);
data = object.getString(s);
}
//TODO 这里将爬取到的数据写到数据库对应的表中
}
}, 0, website.getInterval());
timerMap.put(website.getId(),timer);
}
}
}
return o;
}
public static T create(Class cls){
CrawlerCglibProxy proxy = new CrawlerCglibProxy();
return (T)proxy.getProxy(cls);
}
}
import java.util.ArrayList;
import java.util.List;
/**
* 网站爬虫输出参数
*
* @author liyi
* @create 2018-03-17 17:04
**/
public class CrawlerWebsiteModelOut extends BaseModelOut {
private String url;
private Long interval;
private Integer websiteType;
private String websiteName;
private String sourceLink;
private String dataField;
private List contentList = new ArrayList();
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Long getInterval() {
return interval;
}
public void setInterval(Long interval) {
this.interval = interval;
}
public Integer getWebsiteType() {
return websiteType;
}
public void setWebsiteType(Integer websiteType) {
this.websiteType = websiteType;
}
public String getWebsiteName() {
return websiteName;
}
public void setWebsiteName(String websiteName) {
this.websiteName = websiteName;
}
public String getSourceLink() {
return sourceLink;
}
public void setSourceLink(String sourceLink) {
this.sourceLink = sourceLink;
}
public String getDataField() {
return dataField;
}
public void setDataField(String dataField) {
this.dataField = dataField;
}
public List getContentList() {
return contentList;
}
public void setContentList(List contentList) {
this.contentList = contentList;
}
}
/**
* 爬虫网站内容输出参数
*/
public class CrawlerWebsiteContentModelOut extends BaseModelOut{
private Long websiteId;
private String contentName;
private String tableName;
private String columnName;
private String returnField;
private Integer fieldType;
public Long getWebsiteId() {
return websiteId;
}
public void setWebsiteId(Long websiteId) {
this.websiteId = websiteId;
}
public String getContentName() {
return contentName;
}
public void setContentName(String contentName) {
this.contentName = contentName;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getReturnField() {
return returnField;
}
public void setReturnField(String returnField) {
this.returnField = returnField;
}
public Integer getFieldType() {
return fieldType;
}
public void setFieldType(Integer fieldType) {
this.fieldType = fieldType;
}
}
import java.util.Date;
/**
* 基础输出参数
*
* @author liyi
* @create 2018-03-17 17:02
**/
public abstract class BaseModelOut{
private Long id;
private Date create;
private Date modified;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getCreate() {
return create;
}
public void setCreate(Date create) {
this.create = create;
}
public Date getModified() {
return modified;
}
public void setModified(Date modified) {
this.modified = modified;
}
}
下面给出测试的主要方法
public static void main(String[] args) {
CrawlerProxy proxy = CrawlerFactory.create();
proxy.start(website);//website即当前要爬取的网站对象,可以从数据库中读取
}
调用main方法启动定时器,定时从指定网站爬取数据。
java爬虫抓取动态网页(爬虫+jsoup轻松爬知乎(一):爬虫语言之美)
网站优化 • 优采云 发表了文章 • 0 个评论 • 32 次浏览 • 2022-02-07 00:07
爬虫+jsoup轻松爬取知乎
爬知乎是用来测试和调试爬虫的,知乎非常容易爬。也建议初学者爬百度知道的知乎和网站。
最近对大数据很感兴趣,在写爬虫的同时也学习了Java。之前很少接触面向对象的编程语言,只有少量的VB基础。在了解了java之后,我发现了面向对象语言的美妙之处。(对于我这种只把编程当成爱好的鱼儿来说)java最美妙的地方就是有丰富的jar包可以调用,还有大神不断更新的jar包。和以前写C语言相比,每一行代码都是自己敲,现在写java,敲一个点,直接调用n个多功能函数,代码质量很高,简直是搬砖升级到摸腿又富又帅!
我一开始写的爬虫没有使用jsoup包。直接用java自带的httpconnect获取,使用parttern、matcher和正则语法过滤标签和元素。正则语法看起来很晕,parttern定义的模板通用性很差。做的爬虫整体代码比较冗长,完全没有代码的美感。
这次写的爬虫调用的是jsoup jar包。jsoup是一个优秀的HTML解析器,可以通过DOM、CSS以及类似jQuery的操作方法来检索和操作数据,并且封装了get方法,可以直接调用获取页面。结合谷歌浏览器抓取页面元素,快感不断。下面简单介绍一下用法。顺便说一句,我将发布 知乎climbing知乎 的代码。
jsoup包的导入就不说了。jsoup 使用的最重要的东西是元素类和 select() 方法。元素类相当于网页元素中的标签,通过select()方法根据一定的条件选择符合条件的标签,形成符合条件的标签数组。element 支持转换成字符串或文本等。总而言之,它非常强大。您只需要了解 select() 方法的过滤规则即可开始使用。但是使用谷歌浏览器!无需担心过滤规则,开始吧!
这是一个例子:
1.打开谷歌浏览器,在单机上右击要抓取的元素,比如我右击“Spring的JavaConfig Annotation文章”并选中勾选,自动跳出源码代码框,并定位到右击元素的位置。
2.右击代码行,复制-->复制选择器
3.这个时候,我们可以贴一下,看看我们复制了什么:
#div_JK > div.item_list > div:nth-child(1) > div.dTit.tracking-ad > a
表示目标在网页代码中的位置,前后每个>代表一个检索条件。然后我们要获取这个标签,只要写:
//下载网页
String URL="输入网址";
Document document=Jsoup.cnnect("URL");
//在下载的document里进行检索的语句
elements test=document.select("#div_JK")
.select("div.item_list").select("div:nth-child(1)").select("div.dTit.tracking-ad").select("a");
//这样test标签就是我们最开始右键单击检查的标签
String Str=test.toString();//将标签转化成字符串
String text=test.text();//将标签里的文本提取出来
//其他转换方法省略,检索到目标标签,提取标签里的特定元素so easy
贴出下面写的爬知乎的代码,网站比如知乎和贴吧都很适合爬。
目标是打印出 知乎 编辑建议的所有热门问题的 URL、问题名称、问题描述和答案。
代码块
简单的java爬虫代码:
package jsouptest;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class JsoupTest {
public static void main(String[] args) throws IOException {
//获取编辑推荐页
Document document=Jsoup.connect("https://www.zhihu.com/explore/recommendations")
//模拟火狐浏览器
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
.get();
Element main=document.getElementById("zh-recommend-list-full");
Elements url=main.select("div").select("div:nth-child(2)")
.select("h2").select("a[class=question_link]");
for(Element question:url){
//输出href后的值,即主页上每个关注问题的链接
String URL=question.attr("abs:href");
//下载问题链接指向的页面
Document document2=Jsoup.connect(URL)
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
.get();
//问题
Elements title=document2.select("#zh-question-title").select("h2").select("a");
//问题描述
Elements detail=document2.select("#zh-question-detail");
//回答
Elements answer=document2.select("#zh-question-answer-wrap")
.select("div.zm-item-rich-text.expandable.js-collapse-body")
.select("div.zm-editable-content.clearfix");
System.out.println("\n"+"链接:"+URL
+"\n"+"标题:"+title.text()
+"\n"+"问题描述:"+detail.text()
+"\n"+"回答:"+answer.text());
}
}
}
获取效果图:
eclipse编辑器不支持自动换行,所以文字堆积在一行。您可以使用文件类将捕获的数据存储在本地 txt 文件或 doc 文件中。
写爬虫的首要目标是抓取携程等机票数据。当然,不是为了大数据分析,而是为了我自己。大家都知道,机票最便宜的时间不是出发前一天,也不是出发前一个月,而是出发前十天或十天左右。此时,机票价格有一个低谷。因此,我想写一个机票爬虫并部署在服务器上,然后编写一个Android app将爬取目标传递给服务器,让爬虫爬取。爬的次数也不多,一天两三次就够了,也省了对反爬虫的研究。当车票进入预期价格或低谷时,只需发送消息通知我并手动购买车票。
是的,如果进展顺利,将有 3-4 次跟进文章,直到该项目完成。为了能多坐几趟航班见见我的小女朋友,祝你成功! 查看全部
java爬虫抓取动态网页(爬虫+jsoup轻松爬知乎(一):爬虫语言之美)
爬虫+jsoup轻松爬取知乎
爬知乎是用来测试和调试爬虫的,知乎非常容易爬。也建议初学者爬百度知道的知乎和网站。
最近对大数据很感兴趣,在写爬虫的同时也学习了Java。之前很少接触面向对象的编程语言,只有少量的VB基础。在了解了java之后,我发现了面向对象语言的美妙之处。(对于我这种只把编程当成爱好的鱼儿来说)java最美妙的地方就是有丰富的jar包可以调用,还有大神不断更新的jar包。和以前写C语言相比,每一行代码都是自己敲,现在写java,敲一个点,直接调用n个多功能函数,代码质量很高,简直是搬砖升级到摸腿又富又帅!
我一开始写的爬虫没有使用jsoup包。直接用java自带的httpconnect获取,使用parttern、matcher和正则语法过滤标签和元素。正则语法看起来很晕,parttern定义的模板通用性很差。做的爬虫整体代码比较冗长,完全没有代码的美感。
这次写的爬虫调用的是jsoup jar包。jsoup是一个优秀的HTML解析器,可以通过DOM、CSS以及类似jQuery的操作方法来检索和操作数据,并且封装了get方法,可以直接调用获取页面。结合谷歌浏览器抓取页面元素,快感不断。下面简单介绍一下用法。顺便说一句,我将发布 知乎climbing知乎 的代码。
jsoup包的导入就不说了。jsoup 使用的最重要的东西是元素类和 select() 方法。元素类相当于网页元素中的标签,通过select()方法根据一定的条件选择符合条件的标签,形成符合条件的标签数组。element 支持转换成字符串或文本等。总而言之,它非常强大。您只需要了解 select() 方法的过滤规则即可开始使用。但是使用谷歌浏览器!无需担心过滤规则,开始吧!
这是一个例子:
1.打开谷歌浏览器,在单机上右击要抓取的元素,比如我右击“Spring的JavaConfig Annotation文章”并选中勾选,自动跳出源码代码框,并定位到右击元素的位置。
2.右击代码行,复制-->复制选择器
3.这个时候,我们可以贴一下,看看我们复制了什么:
#div_JK > div.item_list > div:nth-child(1) > div.dTit.tracking-ad > a
表示目标在网页代码中的位置,前后每个>代表一个检索条件。然后我们要获取这个标签,只要写:
//下载网页
String URL="输入网址";
Document document=Jsoup.cnnect("URL");
//在下载的document里进行检索的语句
elements test=document.select("#div_JK")
.select("div.item_list").select("div:nth-child(1)").select("div.dTit.tracking-ad").select("a");
//这样test标签就是我们最开始右键单击检查的标签
String Str=test.toString();//将标签转化成字符串
String text=test.text();//将标签里的文本提取出来
//其他转换方法省略,检索到目标标签,提取标签里的特定元素so easy
贴出下面写的爬知乎的代码,网站比如知乎和贴吧都很适合爬。
目标是打印出 知乎 编辑建议的所有热门问题的 URL、问题名称、问题描述和答案。
代码块
简单的java爬虫代码:
package jsouptest;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class JsoupTest {
public static void main(String[] args) throws IOException {
//获取编辑推荐页
Document document=Jsoup.connect("https://www.zhihu.com/explore/recommendations")
//模拟火狐浏览器
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
.get();
Element main=document.getElementById("zh-recommend-list-full");
Elements url=main.select("div").select("div:nth-child(2)")
.select("h2").select("a[class=question_link]");
for(Element question:url){
//输出href后的值,即主页上每个关注问题的链接
String URL=question.attr("abs:href");
//下载问题链接指向的页面
Document document2=Jsoup.connect(URL)
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
.get();
//问题
Elements title=document2.select("#zh-question-title").select("h2").select("a");
//问题描述
Elements detail=document2.select("#zh-question-detail");
//回答
Elements answer=document2.select("#zh-question-answer-wrap")
.select("div.zm-item-rich-text.expandable.js-collapse-body")
.select("div.zm-editable-content.clearfix");
System.out.println("\n"+"链接:"+URL
+"\n"+"标题:"+title.text()
+"\n"+"问题描述:"+detail.text()
+"\n"+"回答:"+answer.text());
}
}
}
获取效果图:
eclipse编辑器不支持自动换行,所以文字堆积在一行。您可以使用文件类将捕获的数据存储在本地 txt 文件或 doc 文件中。
写爬虫的首要目标是抓取携程等机票数据。当然,不是为了大数据分析,而是为了我自己。大家都知道,机票最便宜的时间不是出发前一天,也不是出发前一个月,而是出发前十天或十天左右。此时,机票价格有一个低谷。因此,我想写一个机票爬虫并部署在服务器上,然后编写一个Android app将爬取目标传递给服务器,让爬虫爬取。爬的次数也不多,一天两三次就够了,也省了对反爬虫的研究。当车票进入预期价格或低谷时,只需发送消息通知我并手动购买车票。
是的,如果进展顺利,将有 3-4 次跟进文章,直到该项目完成。为了能多坐几趟航班见见我的小女朋友,祝你成功!
java爬虫抓取动态网页( 动态网页爬虫技术一之API请求法安装selenium模块下载(组图))
网站优化 • 优采云 发表了文章 • 0 个评论 • 53 次浏览 • 2022-02-06 19:13
动态网页爬虫技术一之API请求法安装selenium模块下载(组图))
本节课我给大家讲解一个稍微复杂一点的爬虫,也就是动态网页的爬虫。
动态网页技术简介
动态网络爬虫技术的API请求方法
动态网络爬虫技术二:模拟浏览器方法
安装 selenium 模块下载
谷歌浏览器驱动安装
ChromeDriver以某宝藏松鼠店为例,抓取“坚果炒货”的商品名称、价格、销量和评论数
课后作业
关于作者
动态网页技术简介
所谓动态网页,是指相对于静态网页的一种网页编程技术。对于静态网页,随着html代码的生成,页面的内容和显示效果基本不会改变——除非你修改了页面代码。动态网页并非如此。虽然页面代码没有改变,但是显示的内容会随着时间、环境或数据库操作的结果而改变。
值得强调的是,动态网页不应与页面内容是否动态相混淆。这里所说的动态网页与网页上的各种动画、滚动字幕等视觉动态效果没有直接关系。动态网页也可以是纯文本内容或收录各种动画内容。这些只是特定于网页。内容的呈现形式,无论网页是否具有动态效果,只要是通过动态网站技术生成的,都可以称为动态网页。(说明来源:百度百科-《动态网页》,如链接失效请访问:%E5%8A%A8%E6%80%81%E7%BD%91%E9%A1%B5/6327050?fr=阿拉丁)
互联网每天都在蓬勃发展,数以万计的网络平台雨后春笋般涌现。不同平台针对不同用户的权限和偏好推出不同的个性化内容。看来,传统的静态网页早已无法满足社会的需求。于是,动态网页技术应运而生。当然,在对网页加载速度要求越来越高的情况下,异步加载成为了很多大型网站的首选。比如各大电商平台、知识型网站、社交平台等,都广泛采用了异步加载的动态技术。简单来说就是加载一些根据时间和请求变化的内容,比如某宝的商品价格和评论,比如某阀门的热门影评,某条新闻的视频等,通过先加载网页整体框架,再加载。呈现动态内容。
对于这种类型的动态页面,如果我们使用上面提到的静态网页爬虫的方法来爬取,可能不会得到任何结果,因为大部分异步加载的内容都位于请求该内容的一段JS代码中。在一定的触发操作下,这些JS代码开始工作,从数据库中提取相应的数据,放到网页框架中的相应位置,最后拼接成一个我们可以看到的完整页面。
动态网络爬虫技术的API请求方法
看似复杂的操作,看似给我们的爬虫带来了不少麻烦,但其实也可能给我们带来很大的方便。我们只需要找到JS请求的API,按照一定的要求发送带有有效参数的请求,就可以得到最干净的数据,而不是像以前那样从嵌套的HTML代码中慢慢解析出我们想要的HTML代码。所需的数据。
这里我们以上面提到的豆瓣电影(如果链接失效请访问:#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0)为例进行制作分析,提取豆瓣前100名电影的名称和评分及其地址。
这是按人气排序的近期热门电影的截图。每个月都有不同的新电影上映,每部电影都会因为口碑效应而呈现出不同的热度排名。如果这个页面是静态网页,那么豆瓣程序员每天上网修改这个页面是不是很辛苦。所以,我们可以大胆猜测这是一个动态页面。但猜测是不够的,我们必须证明它。这里我们将使用第二讲中提到的谷歌开发者工具。按F12或者在网页空白处右键选择Inspect(N),或者按键盘上的组合键Ctrl+Shift+I来召唤我们的神器。如下所示:
今天我们不再使用左上角的鼠标按钮,而是使用红色框中的Network,显示了网页加载的所有文件,如下图所示:
如果下面没有结果,您需要在打开 Google Developer Tools 的情况下刷新页面。
如上图所示,我们可以通过点击上方小红框内的“XHR”按钮来过滤这个网页中异步加载的内容。至于哪一个是我们想要的,这是一个问题。看左边的地址,我们好像看不出什么端倪,我们来一一看看吧。. . 经过枚举,我们发现第三个就是我们想要的内容,其内容如下:
我们可以看到这个链接中收录的内容是以 JSON 格式显示的。这时候我们就有了一个大概的思路,就是用requests模块下载这个链接的内容,然后用python的json模块下载内容。解析。
但是,这似乎是一页,并且只有 20 部电影要数,而我们要的是前 100 部电影,如何做到这一点?
没办法,毕竟是动态网页,内容可以根据请求改变,而且这里也没有登录操作,打开网页就可以看到,那我们可以换个网址来获取到下一页甚至下一页 页面的内容?当然可以,不然我就写不出来了!
让我们仔细看看这个 URL 中传递的参数:
至此,我们可能不知道这五个参数是干什么用的,但是我们可以找到规律,所以现在回到原来的网页,点击页面底部的“加载更多”,然后返回给开发者工具,哇,多了一个网址,就是刚才说的那个,内容也只要:
此 URL 还传递五个参数:
唯一的区别是名为“page_start”的关键字的值发生了变化。简单地把它翻译成页面的起点。看上面的“page_limit”,大概就是页数限制的意思。看右边的响应内容,这个页面传递了20个条目,也就是说“page_limit”是一个页面的条目数限制,也就是20,这个数据不变,而“page_start”是本页开头的条目号,那么我们要获取下面的内容,改“page_start”不就够了吗?是的。
老规矩,先写个代码
# -*- coding: utf-8 -*-
import requests
import jsonfor i in range(5):
page_start = str(i * 20) # 注释1
url = 'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=' + page_start # 注释2
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}
response = requests.get(url=url, headers=headers, verify=False)
content = response.content.decode()
content_list = json.loads(content)['subjects'] # 注释3for item in content_list: # 注释4
title = item['title'] #注释5
rate = item['rate'] # 注释6
link = item['url'] # 注释7
print(title, rate, link)
最后,可以使用标准输入流写入txt文件,也可以使用xlwt模块写入EXCEL,也可以使用pymysql模块写入Mysql数据库。
至此,这种寻找API并传递有效参数重放API的方法已经介绍给大家了。这是一种很常用的方法,可以在很多网站中使用,而且速度非常快,结果也是最简洁的。.
动态网络爬虫技术二:模拟浏览器方法
虽然我们上面提到的API请求方式好用又快,但并不是所有的网站都会使用这种异步加载方式来实现网站,还有一些网站会采取反爬措施爬虫,比如常见的验证码。虽然验证码主要是用来防止CSRF攻击的,但也有网站用来对付爬虫的,比如某宝。这时候我们要介绍另一个神器,Python的Selenium模块。
Selenium 是用于 Web 应用程序测试的工具。Selenium 测试直接在浏览器中运行,就像真正的用户一样。支持的浏览器包括 IE (7, 8, 9, 10, 11), Mozilla Firefox, Safari, Google Chrome, Opera等。该工具的主要功能包括: 测试与浏览器的兼容性 - 测试看看你的应用程序是否(解释来自:百度百科-“Selenium”,如果链接失效请点击)
简单来说,Selenium 是一个主要用于自动化测试的工具。它可以运行在各种带有浏览器驱动程序的浏览器中,并根据代码自动模拟人类操作来获取或控制网页元素。当然,Selenium 不是 Python 的产品,而是一个独立的项目,Python 提供了对 Selenium 的支持。(您可以自行访问 Selenium 的主页,如果链接无效,请点击)
安装硒模块
要使用Selenium这样的第三方工具,我们首先要安装它,这里还是使用pip工具。以管理员权限运行命令行,输入pip install selenium,稍等片刻即可完成安装,如果觉得官方pypi镜像网速慢,可以使用国内豆瓣镜像源,pip install selenium -i ,加上这个 -i 参数和豆瓣pypi镜像的地址就够了。如果要默认使用豆瓣镜像源,请自行百度修改方法。
下载谷歌浏览器驱动
安装成功后,我们需要安装下一个必要的东西,浏览器驱动程序。前面提到,selenium 需要配合浏览器驱动运行,所以我们以安装 Google Chrome Driver 为例。
首先,我们需要查看我们的谷歌浏览器版本,可以在谷歌的“帮助”中查看。具体方法是打开Chrome,点击右上角的三个点状按钮,然后在弹出的菜单中依次选择Help。(E)->关于谷歌浏览器(G)如下图:
笔者的浏览器更新到最新版本63,老版本的操作方法大致相同。
点击信息后,我们可以看到当前的Chrome版本,下图为示例:
Chrome在不断的升级,所以相应的驱动也要不断的更新和适配Chrome的版本。这里我们需要找到对应的ChromeDriver版本映射,推荐一个持续更新的CSDN博客(如果链接失效请点击:),根据版本映射表,下载对应版本的ChromeDriver,下载地址1()(如果链接失效,请访问:),下载地址2()(如果链接失效,请访问:)。
安装 ChromeDriver
这里需要配置环境变量。正如第一讲中提到的,为“路径”添加一行值。
首先,我们需要找到 Chrome 的安装位置。最简单的方法是在桌面上找到谷歌浏览器的快捷方式,右键单击并选择“打开文件的位置”将其打开。比如我这里打开的路径是C:\Program Files(x86)\Google\Chrome\Application,那我就把这个路径加到Path里面。然后,我们需要把下载的ChromeDriver解压到exe程序中,将单独的exe程序复制到刚才的路径下,如下图:
至此,ChromeDriver 已经完成安装。我们可以在命令行输入命令python进入python交互环境进行测试,如下图所示:
如果你的谷歌浏览器自动打开并跳转到百度首页,那么恭喜~
以某宝的松鼠店为例,抓取“坚果炒货”的品名、价格、销量和评论数
此页面的 URL 是:#TmshopSrchNav
老规矩,先放一段代码:
# -*- coding: utf-8 -*-
from selenium import webdriver
driver = webdriver.Chrome() # 注释1
url = 'https://sanzhisongshu.tmall.com/category-1124487841.htm?spm=a1z10.1-b-s.w5003-17763072511.42.6995d6732XB8Of&tsearch=y&scene=taobao_shop#TmshopSrchNav'
driver.maximize_window() # 注释2
driver.get(url) # 注释3
dl_list = driver.find_elements_by_class_name('item') # 注释4
for dl in dl_list:
name = dl.find_element_by_css_selector("[class='item-name J_TGoldData']").text # 注释5
price = dl.find_element_by_class_name('cprice-area').text # 注释6
sale = dl.find_element_by_class_name('sale-area').text # 注释7
comment = dl.find_element_by_xpath('//*[@id="J_ShopSearchResult"]/div/div[3]/div[1]/dl[1]/dd[2]/div/h4/a/span').text # 注释8
print(name, price, sale, comment)
driver.close() # 注释9
XPath 代表 XML 路径语言,它是一种用于定位 XML(标准通用标记语言的子集)文档部分的语言。XPath 基于 XML 树结构,有不同类型的节点,包括元素节点、属性节点和文本节点,提供了在数据结构树中查找节点的能力。XPath 的初衷是将其用作 XPointer 和 XSLT 之间的通用语法模型。但是 XPath 作为一种小型查询语言很快被开发人员采用。(解释来自:百度百科-《XPath》,如果链接失效请访问:)
这个例子的最终结果如下:
您仍然可以自由选择数据存储方式。
这里需要注意的是,使用 selenium 进行数据爬取可能比之前的 API 请求方式慢很多。打开到对应的窗口后,窗口可能会长时间没有动作,但这不一定是错误或者是程序卡住的表现,也可能是程序在疯狂搜索网页元素. 在此过程中,如果您不确定是否有错误,请不要进行其他操作,以免有时导致元素失去焦点,导致莫名其妙的错误。
当然,硒的作用远不止这些。它几乎可以模拟人们在网页上可以做的任何行为,包括点击、输入等行为。这个比较适合一些网站填写验证码的你可以自己发现更多有趣的内容。本次讲座写在这里。感谢大家的耐心阅读。
课后作业
这是给你的两个小任务。有兴趣的可以自行测试。
请使用API请求方式在QQ音乐上自行查找歌曲下载,无需登录账号即可下载歌曲。请使用selenium爬取知乎热门话题或话题的首页回答100。
关于作者
作者是一名即将毕业的大四学生。他自学爬虫,是几个爬虫项目的主要开发者。对各种爬虫有一定的了解和项目经验。为大家更新。作者也是一个狂热的信息安全爱好者。谢谢你的支持。 查看全部
java爬虫抓取动态网页(
动态网页爬虫技术一之API请求法安装selenium模块下载(组图))
本节课我给大家讲解一个稍微复杂一点的爬虫,也就是动态网页的爬虫。
动态网页技术简介
动态网络爬虫技术的API请求方法
动态网络爬虫技术二:模拟浏览器方法
安装 selenium 模块下载
谷歌浏览器驱动安装
ChromeDriver以某宝藏松鼠店为例,抓取“坚果炒货”的商品名称、价格、销量和评论数
课后作业
关于作者
动态网页技术简介
所谓动态网页,是指相对于静态网页的一种网页编程技术。对于静态网页,随着html代码的生成,页面的内容和显示效果基本不会改变——除非你修改了页面代码。动态网页并非如此。虽然页面代码没有改变,但是显示的内容会随着时间、环境或数据库操作的结果而改变。
值得强调的是,动态网页不应与页面内容是否动态相混淆。这里所说的动态网页与网页上的各种动画、滚动字幕等视觉动态效果没有直接关系。动态网页也可以是纯文本内容或收录各种动画内容。这些只是特定于网页。内容的呈现形式,无论网页是否具有动态效果,只要是通过动态网站技术生成的,都可以称为动态网页。(说明来源:百度百科-《动态网页》,如链接失效请访问:%E5%8A%A8%E6%80%81%E7%BD%91%E9%A1%B5/6327050?fr=阿拉丁)
互联网每天都在蓬勃发展,数以万计的网络平台雨后春笋般涌现。不同平台针对不同用户的权限和偏好推出不同的个性化内容。看来,传统的静态网页早已无法满足社会的需求。于是,动态网页技术应运而生。当然,在对网页加载速度要求越来越高的情况下,异步加载成为了很多大型网站的首选。比如各大电商平台、知识型网站、社交平台等,都广泛采用了异步加载的动态技术。简单来说就是加载一些根据时间和请求变化的内容,比如某宝的商品价格和评论,比如某阀门的热门影评,某条新闻的视频等,通过先加载网页整体框架,再加载。呈现动态内容。
对于这种类型的动态页面,如果我们使用上面提到的静态网页爬虫的方法来爬取,可能不会得到任何结果,因为大部分异步加载的内容都位于请求该内容的一段JS代码中。在一定的触发操作下,这些JS代码开始工作,从数据库中提取相应的数据,放到网页框架中的相应位置,最后拼接成一个我们可以看到的完整页面。
动态网络爬虫技术的API请求方法
看似复杂的操作,看似给我们的爬虫带来了不少麻烦,但其实也可能给我们带来很大的方便。我们只需要找到JS请求的API,按照一定的要求发送带有有效参数的请求,就可以得到最干净的数据,而不是像以前那样从嵌套的HTML代码中慢慢解析出我们想要的HTML代码。所需的数据。
这里我们以上面提到的豆瓣电影(如果链接失效请访问:#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0)为例进行制作分析,提取豆瓣前100名电影的名称和评分及其地址。
这是按人气排序的近期热门电影的截图。每个月都有不同的新电影上映,每部电影都会因为口碑效应而呈现出不同的热度排名。如果这个页面是静态网页,那么豆瓣程序员每天上网修改这个页面是不是很辛苦。所以,我们可以大胆猜测这是一个动态页面。但猜测是不够的,我们必须证明它。这里我们将使用第二讲中提到的谷歌开发者工具。按F12或者在网页空白处右键选择Inspect(N),或者按键盘上的组合键Ctrl+Shift+I来召唤我们的神器。如下所示:
今天我们不再使用左上角的鼠标按钮,而是使用红色框中的Network,显示了网页加载的所有文件,如下图所示:
如果下面没有结果,您需要在打开 Google Developer Tools 的情况下刷新页面。
如上图所示,我们可以通过点击上方小红框内的“XHR”按钮来过滤这个网页中异步加载的内容。至于哪一个是我们想要的,这是一个问题。看左边的地址,我们好像看不出什么端倪,我们来一一看看吧。. . 经过枚举,我们发现第三个就是我们想要的内容,其内容如下:
我们可以看到这个链接中收录的内容是以 JSON 格式显示的。这时候我们就有了一个大概的思路,就是用requests模块下载这个链接的内容,然后用python的json模块下载内容。解析。
但是,这似乎是一页,并且只有 20 部电影要数,而我们要的是前 100 部电影,如何做到这一点?
没办法,毕竟是动态网页,内容可以根据请求改变,而且这里也没有登录操作,打开网页就可以看到,那我们可以换个网址来获取到下一页甚至下一页 页面的内容?当然可以,不然我就写不出来了!
让我们仔细看看这个 URL 中传递的参数:
至此,我们可能不知道这五个参数是干什么用的,但是我们可以找到规律,所以现在回到原来的网页,点击页面底部的“加载更多”,然后返回给开发者工具,哇,多了一个网址,就是刚才说的那个,内容也只要:
此 URL 还传递五个参数:
唯一的区别是名为“page_start”的关键字的值发生了变化。简单地把它翻译成页面的起点。看上面的“page_limit”,大概就是页数限制的意思。看右边的响应内容,这个页面传递了20个条目,也就是说“page_limit”是一个页面的条目数限制,也就是20,这个数据不变,而“page_start”是本页开头的条目号,那么我们要获取下面的内容,改“page_start”不就够了吗?是的。
老规矩,先写个代码
# -*- coding: utf-8 -*-
import requests
import jsonfor i in range(5):
page_start = str(i * 20) # 注释1
url = 'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=' + page_start # 注释2
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}
response = requests.get(url=url, headers=headers, verify=False)
content = response.content.decode()
content_list = json.loads(content)['subjects'] # 注释3for item in content_list: # 注释4
title = item['title'] #注释5
rate = item['rate'] # 注释6
link = item['url'] # 注释7
print(title, rate, link)
最后,可以使用标准输入流写入txt文件,也可以使用xlwt模块写入EXCEL,也可以使用pymysql模块写入Mysql数据库。
至此,这种寻找API并传递有效参数重放API的方法已经介绍给大家了。这是一种很常用的方法,可以在很多网站中使用,而且速度非常快,结果也是最简洁的。.
动态网络爬虫技术二:模拟浏览器方法
虽然我们上面提到的API请求方式好用又快,但并不是所有的网站都会使用这种异步加载方式来实现网站,还有一些网站会采取反爬措施爬虫,比如常见的验证码。虽然验证码主要是用来防止CSRF攻击的,但也有网站用来对付爬虫的,比如某宝。这时候我们要介绍另一个神器,Python的Selenium模块。
Selenium 是用于 Web 应用程序测试的工具。Selenium 测试直接在浏览器中运行,就像真正的用户一样。支持的浏览器包括 IE (7, 8, 9, 10, 11), Mozilla Firefox, Safari, Google Chrome, Opera等。该工具的主要功能包括: 测试与浏览器的兼容性 - 测试看看你的应用程序是否(解释来自:百度百科-“Selenium”,如果链接失效请点击)
简单来说,Selenium 是一个主要用于自动化测试的工具。它可以运行在各种带有浏览器驱动程序的浏览器中,并根据代码自动模拟人类操作来获取或控制网页元素。当然,Selenium 不是 Python 的产品,而是一个独立的项目,Python 提供了对 Selenium 的支持。(您可以自行访问 Selenium 的主页,如果链接无效,请点击)
安装硒模块
要使用Selenium这样的第三方工具,我们首先要安装它,这里还是使用pip工具。以管理员权限运行命令行,输入pip install selenium,稍等片刻即可完成安装,如果觉得官方pypi镜像网速慢,可以使用国内豆瓣镜像源,pip install selenium -i ,加上这个 -i 参数和豆瓣pypi镜像的地址就够了。如果要默认使用豆瓣镜像源,请自行百度修改方法。
下载谷歌浏览器驱动
安装成功后,我们需要安装下一个必要的东西,浏览器驱动程序。前面提到,selenium 需要配合浏览器驱动运行,所以我们以安装 Google Chrome Driver 为例。
首先,我们需要查看我们的谷歌浏览器版本,可以在谷歌的“帮助”中查看。具体方法是打开Chrome,点击右上角的三个点状按钮,然后在弹出的菜单中依次选择Help。(E)->关于谷歌浏览器(G)如下图:
笔者的浏览器更新到最新版本63,老版本的操作方法大致相同。
点击信息后,我们可以看到当前的Chrome版本,下图为示例:
Chrome在不断的升级,所以相应的驱动也要不断的更新和适配Chrome的版本。这里我们需要找到对应的ChromeDriver版本映射,推荐一个持续更新的CSDN博客(如果链接失效请点击:),根据版本映射表,下载对应版本的ChromeDriver,下载地址1()(如果链接失效,请访问:),下载地址2()(如果链接失效,请访问:)。
安装 ChromeDriver
这里需要配置环境变量。正如第一讲中提到的,为“路径”添加一行值。
首先,我们需要找到 Chrome 的安装位置。最简单的方法是在桌面上找到谷歌浏览器的快捷方式,右键单击并选择“打开文件的位置”将其打开。比如我这里打开的路径是C:\Program Files(x86)\Google\Chrome\Application,那我就把这个路径加到Path里面。然后,我们需要把下载的ChromeDriver解压到exe程序中,将单独的exe程序复制到刚才的路径下,如下图:
至此,ChromeDriver 已经完成安装。我们可以在命令行输入命令python进入python交互环境进行测试,如下图所示:
如果你的谷歌浏览器自动打开并跳转到百度首页,那么恭喜~
以某宝的松鼠店为例,抓取“坚果炒货”的品名、价格、销量和评论数
此页面的 URL 是:#TmshopSrchNav
老规矩,先放一段代码:
# -*- coding: utf-8 -*-
from selenium import webdriver
driver = webdriver.Chrome() # 注释1
url = 'https://sanzhisongshu.tmall.com/category-1124487841.htm?spm=a1z10.1-b-s.w5003-17763072511.42.6995d6732XB8Of&tsearch=y&scene=taobao_shop#TmshopSrchNav'
driver.maximize_window() # 注释2
driver.get(url) # 注释3
dl_list = driver.find_elements_by_class_name('item') # 注释4
for dl in dl_list:
name = dl.find_element_by_css_selector("[class='item-name J_TGoldData']").text # 注释5
price = dl.find_element_by_class_name('cprice-area').text # 注释6
sale = dl.find_element_by_class_name('sale-area').text # 注释7
comment = dl.find_element_by_xpath('//*[@id="J_ShopSearchResult"]/div/div[3]/div[1]/dl[1]/dd[2]/div/h4/a/span').text # 注释8
print(name, price, sale, comment)
driver.close() # 注释9
XPath 代表 XML 路径语言,它是一种用于定位 XML(标准通用标记语言的子集)文档部分的语言。XPath 基于 XML 树结构,有不同类型的节点,包括元素节点、属性节点和文本节点,提供了在数据结构树中查找节点的能力。XPath 的初衷是将其用作 XPointer 和 XSLT 之间的通用语法模型。但是 XPath 作为一种小型查询语言很快被开发人员采用。(解释来自:百度百科-《XPath》,如果链接失效请访问:)
这个例子的最终结果如下:
您仍然可以自由选择数据存储方式。
这里需要注意的是,使用 selenium 进行数据爬取可能比之前的 API 请求方式慢很多。打开到对应的窗口后,窗口可能会长时间没有动作,但这不一定是错误或者是程序卡住的表现,也可能是程序在疯狂搜索网页元素. 在此过程中,如果您不确定是否有错误,请不要进行其他操作,以免有时导致元素失去焦点,导致莫名其妙的错误。
当然,硒的作用远不止这些。它几乎可以模拟人们在网页上可以做的任何行为,包括点击、输入等行为。这个比较适合一些网站填写验证码的你可以自己发现更多有趣的内容。本次讲座写在这里。感谢大家的耐心阅读。
课后作业
这是给你的两个小任务。有兴趣的可以自行测试。
请使用API请求方式在QQ音乐上自行查找歌曲下载,无需登录账号即可下载歌曲。请使用selenium爬取知乎热门话题或话题的首页回答100。
关于作者
作者是一名即将毕业的大四学生。他自学爬虫,是几个爬虫项目的主要开发者。对各种爬虫有一定的了解和项目经验。为大家更新。作者也是一个狂热的信息安全爱好者。谢谢你的支持。
java爬虫抓取动态网页(教您使用java爬虫geccogeccoJD商品信息商品信息)
网站优化 • 优采云 发表了文章 • 0 个评论 • 48 次浏览 • 2022-02-06 17:23
关于gecco爬虫框架
不了解gecco的可以参考gecco的github主页。gecco 爬虫非常简单易用。有一篇文章文章《教你使用java爬虫gecco抓取京东商品信息》,使用的是传统的注解方式。建议在阅读本文章之前先了解前面的文章。这里我们介绍一下DynamicGecco方法,它比以前更简单。只需要3个品类,就可以把京东的所有产品都抢完。
什么是 DynamicGecco
DynamicGecco的目的是在不定义SpiderBeans的情况下实现爬取规则的运行时配置。实现原理是利用字节码编程动态生成SpiderBeans,通过自定义的GeccoClassLoader实现抓取规则的热部署。通常我们可以使用DynamicGecco来实现以下功能:
规则定义
爬虫的爬取规则,如matchUrl、csspath、ajax等,不需要使用注解注入SpiderBean,直接使用DynamicGecco定义。以下是京东全品抓取规则定义:
public static void main(String[] args) {
//对应原来的Category和HrefBean类
Class category = DynamicGecco.html
.stringField("parentName").csspath("dt a").text.build
.listField("categorys",
DynamicGecco.html
.stringField("url").csspath("a").href.build
.stringField("title").csspath("a").text.build
.register).csspath("dd a").build
.register;
//对应原来的AllSort类
DynamicGecco.html
.gecco("http://www.jd.com/allSort.aspx", "consolePipeline", "allSortJsonPipeline")
.requestField("request").request.build
.listField("mobile", category)
.csspath(".category-items > div:nth-child(1) > div:nth-child(2) > div.mc > div.items > dl").build
.register;
//对应ProductBrief类
Class productBrief = DynamicGecco.html
.stringField("code").csspath(".j-sku-item").attr("data-sku").build
.stringField("title").csspath(".p-name> a > em").text.build
.stringField("preview").csspath(".p-img > a > img").image("", "data-lazy-img", "src").build
.stringField("detailUrl").csspath(".p-name > a").href(true).build
.register;
//对应ProductList类
DynamicGecco.html
.gecco("http://list.jd.com/list.html?cat={cat}&delivery={delivery}&page={page}&JL={JL}&go=0", "consolePipeline", "productListJsonPipeline")
.requestField("request").request.build
.intField("currPage").csspath("#J_topPage > span > b").text.build
.intField("totalPage").csspath("#J_topPage > span > i").text.build
.listField("details", productBrief).csspath("#plist .gl-item").build
.register;
//对应ProductDetail类
DynamicGecco.html
.gecco("http://item.jd.com/{code}.html", "consolePipeline")
.stringField("code").requestParameter.build
.stringField("title").csspath("#name > h1").text.build
.stringField("detail").csspath("#product-detail-2").build
.stringField("image").csspath("#spec-n1 img").image("d:/gecco/jd/img").build
.field("price", FieldType.type(JDPrice.class)).ajax("http://p.3.cn/prices/get%3Ftyp ... %3DJ_{code}").build
.field("jdAd", FieldType.type(JDad.class)).ajax("http://cd.jd.com/promotion/v2?skuId={code}&area=1_2805_2855_0&cat=737%2C794%2C798").build
.register;
HttpGetRequest start = new HttpGetRequest("http://www.jd.com/allSort.aspx");
start.setCharset("GBK");
GeccoEngine.create
.classpath("com.geccocrawler.gecco.demo.jd")
.start(start)
.interval(2000)
.run;
}
规则定义好后,就可以启动GeccoEngine了,和之前一样。可以看出,前面的例子定义了7个bean,但是这里只需要一个类。
语法解释 JsonPipeline
Pipeline 的写法也和以前不一样。因为是运行时生成的bean,所以定义的bean不能像以前那样直接使用。Gecco 会将所有 bean 转换为 JSONObject,并通过 json 操作获取捕获的信息。下面是DynamicJD定义的两条Pipeline:
@PipelineName("allSortJsonPipeline")
public class AllSortJsonPipeline extends JsonPipeline {
public static List sortRequests = new ArrayList;
@Override
public void process(JSONObject allSort) {
HttpRequest currRequest = HttpGetRequest.fromJson(allSort.getJSONObject("request"));
JSONArray categorys = allSort.getJSONArray("mobile");
process(currRequest, categorys);
}
private void process(HttpRequest currRequest, JSONArray categorys) {
if(categorys == null) {
return;
}
for(int i = 0; i < categorys.size; i++) {
JSONObject category = categorys.getJSONObject(i);
JSONArray hrefs = category.getJSONArray("categorys");
for(int j = 0; j < hrefs.size; j++) {
String url = hrefs.getJSONObject(j).getString("url")+"&delivery=1&page=1&JL=4_10_0&go=0";
SchedulerContext.into(currRequest.subRequest(url));
}
}
}
}
产品列表处理Pipeline,对应原ProductListPipeline
@PipelineName("productListPipeline")
public class ProductListPipeline implements Pipeline {
@Override
public void process(ProductList productList) {
HttpRequest currRequest = productList.getRequest;
//下一页继续抓取
int currPage = productList.getCurrPage;
int nextPage = currPage + 1;
int totalPage = productList.getTotalPage;
if(nextPage newRule = DynamicGecco
.html(rule1.getName)
.gecco("https://github.com/xtuhcy/gecco", "consolePipeline")
.intField("fork").csspath(".pagehead-actions li:nth-child(3) .social-count").text.build
.removeField("star")
.loadClass;
//注册新规则
ge.register(newRule);
} catch(Exception ex) {
ex.printStackTrace;
} finally {
//规则更新完毕
ge.endUpdateRule;
}
线下有规矩
已经定义好的规则,我们可以下线如下:
try {
//开始更新规则
ge.beginUpdateRule;
//下线之前的规则
ge.unregister(rule);
} catch(Exception ex) {
ex.printStackTrace;
} finally {
//规则更新完毕
ge.endUpdateRule;
}
至此,爬虫规则的添加/修改/删除已经实现。您可以愉快地配置爬虫规则!
完整的demo代码可以参考github上的源码,位于com.geccocrawler.gecco.demo.dynamic包中。 查看全部
java爬虫抓取动态网页(教您使用java爬虫geccogeccoJD商品信息商品信息)
关于gecco爬虫框架
不了解gecco的可以参考gecco的github主页。gecco 爬虫非常简单易用。有一篇文章文章《教你使用java爬虫gecco抓取京东商品信息》,使用的是传统的注解方式。建议在阅读本文章之前先了解前面的文章。这里我们介绍一下DynamicGecco方法,它比以前更简单。只需要3个品类,就可以把京东的所有产品都抢完。
什么是 DynamicGecco
DynamicGecco的目的是在不定义SpiderBeans的情况下实现爬取规则的运行时配置。实现原理是利用字节码编程动态生成SpiderBeans,通过自定义的GeccoClassLoader实现抓取规则的热部署。通常我们可以使用DynamicGecco来实现以下功能:
规则定义
爬虫的爬取规则,如matchUrl、csspath、ajax等,不需要使用注解注入SpiderBean,直接使用DynamicGecco定义。以下是京东全品抓取规则定义:
public static void main(String[] args) {
//对应原来的Category和HrefBean类
Class category = DynamicGecco.html
.stringField("parentName").csspath("dt a").text.build
.listField("categorys",
DynamicGecco.html
.stringField("url").csspath("a").href.build
.stringField("title").csspath("a").text.build
.register).csspath("dd a").build
.register;
//对应原来的AllSort类
DynamicGecco.html
.gecco("http://www.jd.com/allSort.aspx", "consolePipeline", "allSortJsonPipeline")
.requestField("request").request.build
.listField("mobile", category)
.csspath(".category-items > div:nth-child(1) > div:nth-child(2) > div.mc > div.items > dl").build
.register;
//对应ProductBrief类
Class productBrief = DynamicGecco.html
.stringField("code").csspath(".j-sku-item").attr("data-sku").build
.stringField("title").csspath(".p-name> a > em").text.build
.stringField("preview").csspath(".p-img > a > img").image("", "data-lazy-img", "src").build
.stringField("detailUrl").csspath(".p-name > a").href(true).build
.register;
//对应ProductList类
DynamicGecco.html
.gecco("http://list.jd.com/list.html?cat={cat}&delivery={delivery}&page={page}&JL={JL}&go=0", "consolePipeline", "productListJsonPipeline")
.requestField("request").request.build
.intField("currPage").csspath("#J_topPage > span > b").text.build
.intField("totalPage").csspath("#J_topPage > span > i").text.build
.listField("details", productBrief).csspath("#plist .gl-item").build
.register;
//对应ProductDetail类
DynamicGecco.html
.gecco("http://item.jd.com/{code}.html", "consolePipeline")
.stringField("code").requestParameter.build
.stringField("title").csspath("#name > h1").text.build
.stringField("detail").csspath("#product-detail-2").build
.stringField("image").csspath("#spec-n1 img").image("d:/gecco/jd/img").build
.field("price", FieldType.type(JDPrice.class)).ajax("http://p.3.cn/prices/get%3Ftyp ... %3DJ_{code}").build
.field("jdAd", FieldType.type(JDad.class)).ajax("http://cd.jd.com/promotion/v2?skuId={code}&area=1_2805_2855_0&cat=737%2C794%2C798").build
.register;
HttpGetRequest start = new HttpGetRequest("http://www.jd.com/allSort.aspx");
start.setCharset("GBK");
GeccoEngine.create
.classpath("com.geccocrawler.gecco.demo.jd")
.start(start)
.interval(2000)
.run;
}
规则定义好后,就可以启动GeccoEngine了,和之前一样。可以看出,前面的例子定义了7个bean,但是这里只需要一个类。
语法解释 JsonPipeline
Pipeline 的写法也和以前不一样。因为是运行时生成的bean,所以定义的bean不能像以前那样直接使用。Gecco 会将所有 bean 转换为 JSONObject,并通过 json 操作获取捕获的信息。下面是DynamicJD定义的两条Pipeline:
@PipelineName("allSortJsonPipeline")
public class AllSortJsonPipeline extends JsonPipeline {
public static List sortRequests = new ArrayList;
@Override
public void process(JSONObject allSort) {
HttpRequest currRequest = HttpGetRequest.fromJson(allSort.getJSONObject("request"));
JSONArray categorys = allSort.getJSONArray("mobile");
process(currRequest, categorys);
}
private void process(HttpRequest currRequest, JSONArray categorys) {
if(categorys == null) {
return;
}
for(int i = 0; i < categorys.size; i++) {
JSONObject category = categorys.getJSONObject(i);
JSONArray hrefs = category.getJSONArray("categorys");
for(int j = 0; j < hrefs.size; j++) {
String url = hrefs.getJSONObject(j).getString("url")+"&delivery=1&page=1&JL=4_10_0&go=0";
SchedulerContext.into(currRequest.subRequest(url));
}
}
}
}
产品列表处理Pipeline,对应原ProductListPipeline
@PipelineName("productListPipeline")
public class ProductListPipeline implements Pipeline {
@Override
public void process(ProductList productList) {
HttpRequest currRequest = productList.getRequest;
//下一页继续抓取
int currPage = productList.getCurrPage;
int nextPage = currPage + 1;
int totalPage = productList.getTotalPage;
if(nextPage newRule = DynamicGecco
.html(rule1.getName)
.gecco("https://github.com/xtuhcy/gecco", "consolePipeline")
.intField("fork").csspath(".pagehead-actions li:nth-child(3) .social-count").text.build
.removeField("star")
.loadClass;
//注册新规则
ge.register(newRule);
} catch(Exception ex) {
ex.printStackTrace;
} finally {
//规则更新完毕
ge.endUpdateRule;
}
线下有规矩
已经定义好的规则,我们可以下线如下:
try {
//开始更新规则
ge.beginUpdateRule;
//下线之前的规则
ge.unregister(rule);
} catch(Exception ex) {
ex.printStackTrace;
} finally {
//规则更新完毕
ge.endUpdateRule;
}
至此,爬虫规则的添加/修改/删除已经实现。您可以愉快地配置爬虫规则!
完整的demo代码可以参考github上的源码,位于com.geccocrawler.gecco.demo.dynamic包中。
java爬虫抓取动态网页(爬虫小白给了个任务要抓一些数据,觉着没什么问题)
网站优化 • 优采云 发表了文章 • 0 个评论 • 96 次浏览 • 2022-02-05 14:02
爬虫小白,昨天领导给了一个任务,抓一些数据。看完下一页,我以为是简单的页面分析。我觉得没有问题。
页:
要求:高校、专业查询的数据按原样采集
1、问题
最初采用requests+BeautifulSoup分析的方式,抓取高校查询的数据没有问题(代码在最后),但是抓取专业查询的数据时,出现了不一致抓到的页面和浏览器看到的,每次爬取的都是高校查询的数据,修改参数也没用。应该是js的问题(懂的可以告诉我)。
查了半天,问题还是没有解决。我只能叫大佬(大佬厉害)。大佬推荐使用pyppeteer。
2、pyppeteer 安装
在 Anaconda Prompt 中执行
pip install pyppeteer -i https://pypi.tuna.tsinghua.edu.cn/simple
安装时出错:
Cannot uninstall ‘certifi‘. It is a distutils installed project and thus we cannot accurately determ
解决方案:
Chromium 会在第一次执行 pyppeteer 程序时自动下载。如果网络不允许,可以离线下载安装
2、解决问题
所有设备都安装好了,你可以在这里阅读并开始解决问题。仿真过程如下:
① 进入页面;
② 点击专业查询;
③ 点击查询;
④ 分析数据; 查看全部
java爬虫抓取动态网页(爬虫小白给了个任务要抓一些数据,觉着没什么问题)
爬虫小白,昨天领导给了一个任务,抓一些数据。看完下一页,我以为是简单的页面分析。我觉得没有问题。
页:
要求:高校、专业查询的数据按原样采集
1、问题
最初采用requests+BeautifulSoup分析的方式,抓取高校查询的数据没有问题(代码在最后),但是抓取专业查询的数据时,出现了不一致抓到的页面和浏览器看到的,每次爬取的都是高校查询的数据,修改参数也没用。应该是js的问题(懂的可以告诉我)。
查了半天,问题还是没有解决。我只能叫大佬(大佬厉害)。大佬推荐使用pyppeteer。
2、pyppeteer 安装
在 Anaconda Prompt 中执行
pip install pyppeteer -i https://pypi.tuna.tsinghua.edu.cn/simple
安装时出错:
Cannot uninstall ‘certifi‘. It is a distutils installed project and thus we cannot accurately determ
解决方案:
Chromium 会在第一次执行 pyppeteer 程序时自动下载。如果网络不允许,可以离线下载安装
2、解决问题
所有设备都安装好了,你可以在这里阅读并开始解决问题。仿真过程如下:
① 进入页面;
② 点击专业查询;
③ 点击查询;
④ 分析数据;
java爬虫抓取动态网页(动态web的网络爬虫的历史及现状(组图)!)
网站优化 • 优采云 发表了文章 • 0 个评论 • 54 次浏览 • 2022-02-04 14:07
动态网页的网络爬虫研究 1 网络爬虫的历史与现状 网络爬虫是一种自动提取网页的程序。如果将互联网比作蜘蛛网,那么爬虫就是在网络上四处爬行的蜘蛛。传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在对网页进行爬取的过程中,不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。如果把整个互联网看成一个网站,那么网络蜘蛛就可以利用这个原理爬取互联网上的所有网页。随着互联网从Web1.0时代到Web2.0时代的快速发展,由于Ajax异步加载的特点,为了减轻服务器压力,基于Ajax的动态加载技术解决方案已成为大公司的首选。但随着移动互联网的兴起,JavaScript在移动端和PC端的优良特性得到广泛发挥,基于前端MVC/MVVM的模型逐渐进入各大互联网公司的首选方案。数据显示,2011年互联网上动态网页与静态网页的比例为12.1:1。2014年,动态网页与静态网页的比例攀升至22:1。动态网页的急剧崛起,让各大搜索引擎公司觉得基于动态网页的网络爬虫将变得越来越重要。2 问题现状及解决方案2.
传统爬虫根据url对页面进行爬取,解析页面内容提取新的url用于下一次爬取机制,难以完成。其次,现在网上有很多对实时性要求很高的网站,比如股票、优采云票等等,这些网站里面收录了很多数据并随着服务器不断更新。搜索引擎在抓取这些数据时,由于数据需要下载到本地,所以一直存在数据同步的问题,但是这些实时数据的商业价值非常大。因此,简单来说,当前搜索引擎爬虫系统遇到动态网页时的主要问题是:(1)无法提取Ajax加载的动态页面中的url。(2) 基于 HTTP 请求-响应模型。用户在浏览器中输入一个网页的url,客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回该页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。基于 HTTP 请求-响应模型。用户在浏览器中输入一个网页的url,客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回该页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@>文本对象模型(DOM)。DOM用于访问和处理HTML和XML文档。它可以构造HTML和XML文档。(4)正则表达式。根据正则的优良特性of 表达式可以根据条件快速提取 HTML 文本中的指定元素。所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@>文本对象模型(DOM)。DOM用于访问和处理HTML和XML文档。它可以构造HTML和XML文档。(4)正则表达式。根据正则的优良特性of 表达式可以根据条件快速提取 HTML 文本中的指定元素。
2.3 解决方案 AJAX 使用 JavaScript 驱动的异步请求/响应机制。而且,在 Ajax 应用中,JavaScript 会对 DOM 结构进行大量的更改,甚至页面的所有内容都是通过 JavaScript 直接从服务器读取和动态绘制的。因此,爬虫引擎不能仅仅由基于HTTP的协议驱动,而必须由事件驱动。对于实时数据,系统的实时特性主要体现在两个方面:数据更新的实时性;数据变化后其他服务的实时性。面对海量数据,由于捕捉能力有限,无法快速更新所有数据信息。为了保证用户对实时数据的高要求,热门数据的数据更新应尽可能优先,因此实时捕获数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。所以实时捕捉数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。所以实时捕捉数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。
这种实时爬取策略称为“查询驱动爬取”(QTC,Query Triggered Crawling)。价格服务器除了实时捕捉和管理所有商品的价格外,还需要向其他服务提供价格变化的更新事件(如降价提醒、全网比价等)。如何让其他服务获得实时的商品价格变化信息?我们首先介绍观察者模式。观察者模式(也称为发布/订阅模式)是一种软件设计模式。在这种模式中,目标对象管理依赖它的所有观察者对象,并在其自身状态发生变化时主动发送通知。这通常通过调用每个观察者提供的方法来完成。这种模式通常用于实现事件处理系统。观察者模式在数据变化的实时通知中得到了广泛的应用,使得服务具有高集群、低耦合的特点。根据不同的应用,爬虫系统在很多方面都有所不同。一般来说,爬虫可以分为以下三种: 批量爬虫:批量爬虫具有比较明确的抓取范围和目标。当达到这个设定目标时,爬行过程停止。至于具体的目标,可能会有所不同,可能设置一定数量的要爬取的网页就够了,也可能是设置爬取所消耗的时间。增量爬虫:与批量爬虫不同,增量爬虫会保持连续爬取。对于被抓取的网页,它们应该定期更新,因为互联网的网页在不断变化,新的网页不断增加。网页被删除或网页内容发生变化是常有的事,增量爬虫需要及时反映这种变化,所以在持续的爬取过程中,要么是爬取新的网页,要么是更新已有的网页.
常见的商业搜索引擎爬虫基本属于这一类。垂直爬虫(Focused Crawter):垂直爬虫专注于特定主题内容IC或属于特定行业的网页。例如,对于在线旅游,您只需要从互联网页面中找到与在线旅游相关的页面内容。不考虑其他行业内容。垂直爬虫最大的特点和难点之一是如何识别网页内容是否属于指定行业或主题。从节省系统资源的角度来看,不可能把所有的网页都下载下来再过滤。这种资源浪费太多了。爬虫往往需要在爬取阶段动态识别某个URL是否与主题相关。并且尽量不要去抓取不相关的页面,以达到节省资源的目的。垂直搜索网站或垂直行业网站往往需要这种爬虫。3 结束语对于使用JavaScript进行动态页面的爬取,主要的技术方案有:(1)基于事件驱动的爬虫机制。(2)使用观察者模式和查询驱动的爬取方式捕获Get实时数据,并介绍目前流行的爬虫爬取方案。使用观察者模式和查询驱动的爬取方式获取实时数据。并介绍目前流行的爬虫爬取方案。使用观察者模式和查询驱动的爬取方式获取实时数据。并介绍目前流行的爬虫爬取方案。 查看全部
java爬虫抓取动态网页(动态web的网络爬虫的历史及现状(组图)!)
动态网页的网络爬虫研究 1 网络爬虫的历史与现状 网络爬虫是一种自动提取网页的程序。如果将互联网比作蜘蛛网,那么爬虫就是在网络上四处爬行的蜘蛛。传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在对网页进行爬取的过程中,不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。如果把整个互联网看成一个网站,那么网络蜘蛛就可以利用这个原理爬取互联网上的所有网页。随着互联网从Web1.0时代到Web2.0时代的快速发展,由于Ajax异步加载的特点,为了减轻服务器压力,基于Ajax的动态加载技术解决方案已成为大公司的首选。但随着移动互联网的兴起,JavaScript在移动端和PC端的优良特性得到广泛发挥,基于前端MVC/MVVM的模型逐渐进入各大互联网公司的首选方案。数据显示,2011年互联网上动态网页与静态网页的比例为12.1:1。2014年,动态网页与静态网页的比例攀升至22:1。动态网页的急剧崛起,让各大搜索引擎公司觉得基于动态网页的网络爬虫将变得越来越重要。2 问题现状及解决方案2.
传统爬虫根据url对页面进行爬取,解析页面内容提取新的url用于下一次爬取机制,难以完成。其次,现在网上有很多对实时性要求很高的网站,比如股票、优采云票等等,这些网站里面收录了很多数据并随着服务器不断更新。搜索引擎在抓取这些数据时,由于数据需要下载到本地,所以一直存在数据同步的问题,但是这些实时数据的商业价值非常大。因此,简单来说,当前搜索引擎爬虫系统遇到动态网页时的主要问题是:(1)无法提取Ajax加载的动态页面中的url。(2) 基于 HTTP 请求-响应模型。用户在浏览器中输入一个网页的url,客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回该页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。基于 HTTP 请求-响应模型。用户在浏览器中输入一个网页的url,客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回该页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。客户端向服务器发送请求,服务器收到请求后,如果没有错误,就会返回页面。(2)HTML标签和结构。用户在页面上看到的显示是基于HTML显示的,所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@ > 文本对象模型(DOM)。DOM 用于访问和处理 HTML 和 XML 文档。它可以构造 HTML 和 XML 文档。(4)正则表达式。根据正则表达式的优良特性可以快速提取指定元素在基于条件的 HTML 文本中。所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@>文本对象模型(DOM)。DOM用于访问和处理HTML和XML文档。它可以构造HTML和XML文档。(4)正则表达式。根据正则的优良特性of 表达式可以根据条件快速提取 HTML 文本中的指定元素。所以爬虫需要解析HTML页面,提取页面中的内容。url信息(3)@>文本对象模型(DOM)。DOM用于访问和处理HTML和XML文档。它可以构造HTML和XML文档。(4)正则表达式。根据正则的优良特性of 表达式可以根据条件快速提取 HTML 文本中的指定元素。
2.3 解决方案 AJAX 使用 JavaScript 驱动的异步请求/响应机制。而且,在 Ajax 应用中,JavaScript 会对 DOM 结构进行大量的更改,甚至页面的所有内容都是通过 JavaScript 直接从服务器读取和动态绘制的。因此,爬虫引擎不能仅仅由基于HTTP的协议驱动,而必须由事件驱动。对于实时数据,系统的实时特性主要体现在两个方面:数据更新的实时性;数据变化后其他服务的实时性。面对海量数据,由于捕捉能力有限,无法快速更新所有数据信息。为了保证用户对实时数据的高要求,热门数据的数据更新应尽可能优先,因此实时捕获数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。所以实时捕捉数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。所以实时捕捉数据点的选择更为关键。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。这里我们以购物助手的浏览记录和购物搜索的查询记录作为热门产品的例子。具体过程如下:当用户浏览某个商品时,购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。购物助手获取用户浏览过的商品的URL和该商品在其他商城的URL列表,发送给任务调度服务器。将任务分配给抓取服务器,抓取服务器解析新价格并将其发送到结果存储服务器。结果存储服务器完成数据更新并通知其他价格事件监听器。这样就完成了整个查询驱动的实时爬取过程。
这种实时爬取策略称为“查询驱动爬取”(QTC,Query Triggered Crawling)。价格服务器除了实时捕捉和管理所有商品的价格外,还需要向其他服务提供价格变化的更新事件(如降价提醒、全网比价等)。如何让其他服务获得实时的商品价格变化信息?我们首先介绍观察者模式。观察者模式(也称为发布/订阅模式)是一种软件设计模式。在这种模式中,目标对象管理依赖它的所有观察者对象,并在其自身状态发生变化时主动发送通知。这通常通过调用每个观察者提供的方法来完成。这种模式通常用于实现事件处理系统。观察者模式在数据变化的实时通知中得到了广泛的应用,使得服务具有高集群、低耦合的特点。根据不同的应用,爬虫系统在很多方面都有所不同。一般来说,爬虫可以分为以下三种: 批量爬虫:批量爬虫具有比较明确的抓取范围和目标。当达到这个设定目标时,爬行过程停止。至于具体的目标,可能会有所不同,可能设置一定数量的要爬取的网页就够了,也可能是设置爬取所消耗的时间。增量爬虫:与批量爬虫不同,增量爬虫会保持连续爬取。对于被抓取的网页,它们应该定期更新,因为互联网的网页在不断变化,新的网页不断增加。网页被删除或网页内容发生变化是常有的事,增量爬虫需要及时反映这种变化,所以在持续的爬取过程中,要么是爬取新的网页,要么是更新已有的网页.
常见的商业搜索引擎爬虫基本属于这一类。垂直爬虫(Focused Crawter):垂直爬虫专注于特定主题内容IC或属于特定行业的网页。例如,对于在线旅游,您只需要从互联网页面中找到与在线旅游相关的页面内容。不考虑其他行业内容。垂直爬虫最大的特点和难点之一是如何识别网页内容是否属于指定行业或主题。从节省系统资源的角度来看,不可能把所有的网页都下载下来再过滤。这种资源浪费太多了。爬虫往往需要在爬取阶段动态识别某个URL是否与主题相关。并且尽量不要去抓取不相关的页面,以达到节省资源的目的。垂直搜索网站或垂直行业网站往往需要这种爬虫。3 结束语对于使用JavaScript进行动态页面的爬取,主要的技术方案有:(1)基于事件驱动的爬虫机制。(2)使用观察者模式和查询驱动的爬取方式捕获Get实时数据,并介绍目前流行的爬虫爬取方案。使用观察者模式和查询驱动的爬取方式获取实时数据。并介绍目前流行的爬虫爬取方案。使用观察者模式和查询驱动的爬取方式获取实时数据。并介绍目前流行的爬虫爬取方案。
java爬虫抓取动态网页(一个通用的网络爬虫的基本结构及工作流程(组图))
网站优化 • 优采云 发表了文章 • 0 个评论 • 72 次浏览 • 2022-02-02 20:10
1、MOOC的爬虫教程
2、%2Fbook%2F1709
网络爬虫是搜索引擎爬虫系统的重要组成部分。爬虫的主要目的是将互联网上的网页下载到本地,形成网络内容的镜像备份。本篇博客主要对爬虫和爬虫系统进行简要概述。
一、网络爬虫的基本结构和工作流程
一个通用网络爬虫的框架如图所示:
网络爬虫的基本工作流程如下:
1.首先选择一个精心挑选的种子 URL 的子集;
2.将这些网址放入待抓取的网址队列中;
3. 从待爬取的URL队列中取出待爬取的URL,解析DNS,得到主机的IP,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URL 队列。
4.解析URL队列中已经爬取的URL,分析其中的其他URL,将URL放入待爬取的URL队列,从而进入下一个循环。
二、从爬虫的角度划分互联网
相应地,互联网上的所有页面可以分为五个部分:
1.下载了未过期的网页
2.已下载和过期网页:抓取的网页实际上是互联网内容的镜像和备份。互联网是动态变化的,互联网上的一些内容也发生了变化。您访问的页面已过期。
3.待下载网页:URL队列中待抓取的页面
4. 已知网页:尚未被爬取,也不在待爬取的URL队列中,但分析已爬取的页面得到的URL或待爬取URL对应的页面可以被认为是一个已知的网页。
5.还有一些网页是爬虫无法直接爬取下载的。称为不可知网页。
三、抓取策略
在爬虫系统中,待爬取的 URL 队列是一个重要的部分。待爬取的URL队列中的URL的排列顺序也是一个重要的问题,因为它涉及到先爬到哪个页面,再爬到哪个页面。确定这些 URL 排列顺序的方法称为爬取策略。下面重点介绍几种常见的爬取策略:
1.深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,每次一个链接跟踪每个链接,处理完该行后移动到下一个起始页,并继续跟踪该链接。我们以下图为例:
遍历的路径:AFG EHI BCD
2.广度优先遍历策略
广度优先遍历的基本思想是将新下载的网页中找到的链接直接插入待爬取URL队列的末尾。也就是说,网络爬虫会先爬取起始网页链接的所有网页,然后选择其中一个链接的网页,继续爬取该网页链接的所有网页。或者以上图为例:
遍历路径:ABCDEF GHI
3.反向链接计数策略
反向链接数是指从其他网页指向一个网页的链接数。反向链接的数量表示网页内容被他人推荐的程度。因此,在很多情况下,搜索引擎的爬取系统会使用这个指标来评估网页的重要性,从而确定不同网页的爬取顺序。
在真实的网络环境中,由于广告链接和作弊链接的存在,反向链接的数量并不能完全等同于他人的重要性。因此,搜索引擎倾向于考虑一些可靠的反向链接计数。
4.部分PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于下载的网页,与待爬取的URL队列中的URL一起形成一组网页,计算每个页面的PageRank值. URL 按 PageRank 值排序,并按该顺序抓取页面。
如果每次爬取一个页面都重新计算一次PageRank值,一个折中的方案是每次爬取K个页面都重新计算一次PageRank值。但是这种情况还是有一个问题:对于下载页面中分析的链接,也就是我们前面提到的那部分未知网页,暂时没有PageRank值。为了解决这个问题,给这些页面一个临时的PageRank值:把这个网页的所有传入链接传入的PageRank值聚合起来,从而形成未知页面的PageRank值,从而参与排序. 以下示例说明:
5.OPIC 政策政策
该算法实际上为页面分配了一个重要性分数。在算法开始之前,所有页面都会获得相同的初始现金。当某个页面P被下载时,P的现金分配给从P分析的所有链接,P的现金被清空。根据现金数量对待爬取URL队列中的所有页面进行排序。
6.大网站优先策略
所有待爬取的URL队列中的网页都按照它们所属的网站进行分类。网站需要下载的页面较多,请先下载。这种策略也称为大站点优先策略。 查看全部
java爬虫抓取动态网页(一个通用的网络爬虫的基本结构及工作流程(组图))
1、MOOC的爬虫教程
2、%2Fbook%2F1709
网络爬虫是搜索引擎爬虫系统的重要组成部分。爬虫的主要目的是将互联网上的网页下载到本地,形成网络内容的镜像备份。本篇博客主要对爬虫和爬虫系统进行简要概述。
一、网络爬虫的基本结构和工作流程
一个通用网络爬虫的框架如图所示:

网络爬虫的基本工作流程如下:
1.首先选择一个精心挑选的种子 URL 的子集;
2.将这些网址放入待抓取的网址队列中;
3. 从待爬取的URL队列中取出待爬取的URL,解析DNS,得到主机的IP,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URL 队列。
4.解析URL队列中已经爬取的URL,分析其中的其他URL,将URL放入待爬取的URL队列,从而进入下一个循环。
二、从爬虫的角度划分互联网
相应地,互联网上的所有页面可以分为五个部分:

1.下载了未过期的网页
2.已下载和过期网页:抓取的网页实际上是互联网内容的镜像和备份。互联网是动态变化的,互联网上的一些内容也发生了变化。您访问的页面已过期。
3.待下载网页:URL队列中待抓取的页面
4. 已知网页:尚未被爬取,也不在待爬取的URL队列中,但分析已爬取的页面得到的URL或待爬取URL对应的页面可以被认为是一个已知的网页。
5.还有一些网页是爬虫无法直接爬取下载的。称为不可知网页。
三、抓取策略
在爬虫系统中,待爬取的 URL 队列是一个重要的部分。待爬取的URL队列中的URL的排列顺序也是一个重要的问题,因为它涉及到先爬到哪个页面,再爬到哪个页面。确定这些 URL 排列顺序的方法称为爬取策略。下面重点介绍几种常见的爬取策略:
1.深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,每次一个链接跟踪每个链接,处理完该行后移动到下一个起始页,并继续跟踪该链接。我们以下图为例:

遍历的路径:AFG EHI BCD
2.广度优先遍历策略
广度优先遍历的基本思想是将新下载的网页中找到的链接直接插入待爬取URL队列的末尾。也就是说,网络爬虫会先爬取起始网页链接的所有网页,然后选择其中一个链接的网页,继续爬取该网页链接的所有网页。或者以上图为例:
遍历路径:ABCDEF GHI
3.反向链接计数策略
反向链接数是指从其他网页指向一个网页的链接数。反向链接的数量表示网页内容被他人推荐的程度。因此,在很多情况下,搜索引擎的爬取系统会使用这个指标来评估网页的重要性,从而确定不同网页的爬取顺序。
在真实的网络环境中,由于广告链接和作弊链接的存在,反向链接的数量并不能完全等同于他人的重要性。因此,搜索引擎倾向于考虑一些可靠的反向链接计数。
4.部分PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于下载的网页,与待爬取的URL队列中的URL一起形成一组网页,计算每个页面的PageRank值. URL 按 PageRank 值排序,并按该顺序抓取页面。
如果每次爬取一个页面都重新计算一次PageRank值,一个折中的方案是每次爬取K个页面都重新计算一次PageRank值。但是这种情况还是有一个问题:对于下载页面中分析的链接,也就是我们前面提到的那部分未知网页,暂时没有PageRank值。为了解决这个问题,给这些页面一个临时的PageRank值:把这个网页的所有传入链接传入的PageRank值聚合起来,从而形成未知页面的PageRank值,从而参与排序. 以下示例说明:
5.OPIC 政策政策
该算法实际上为页面分配了一个重要性分数。在算法开始之前,所有页面都会获得相同的初始现金。当某个页面P被下载时,P的现金分配给从P分析的所有链接,P的现金被清空。根据现金数量对待爬取URL队列中的所有页面进行排序。
6.大网站优先策略
所有待爬取的URL队列中的网页都按照它们所属的网站进行分类。网站需要下载的页面较多,请先下载。这种策略也称为大站点优先策略。
java爬虫抓取动态网页(即为如何通过selenium-java爬取异步加载的数据的方法)
网站优化 • 优采云 发表了文章 • 0 个评论 • 59 次浏览 • 2022-02-02 20:10
在之前的系列文章中介绍了如何使用httpclient抓取页面html以及如何使用jsoup分析html源文件的内容得到我们想要的数据,但是有时候这两种方法都不能使用捕获我们想要的数据。所需数据,例如,请参见以下示例。
1.需求场景:
如果要抢到股票的最新价格,F12页信息如下:
按照前面的方法,爬取的代码如下:
/**
* @description: 爬取股票的最新股价
* @author: JAVA开发老菜鸟
* @date: 2021-10-16 21:47
*/
public class StockPriceSpider {
Logger logger = LoggerFactory.getLogger(this.getClass());
public static void main(String[] args) {
StockPriceSpider stockPriceSpider = new StockPriceSpider();
String html = stockPriceSpider.httpClientProcess();
stockPriceSpider.jsoupProcess(html);
}
private String httpClientProcess() {
String html = "";
String uri = "http://quote.eastmoney.com/sh600036.html";
//1.生成httpclient,相当于该打开一个浏览器
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
//2.创建get请求,相当于在浏览器地址栏输入 网址
HttpGet request = new HttpGet(uri);
try {
request.setHeader("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36");
request.setHeader("accept", "application/json, text/javascript, */*; q=0.01");
// HttpHost proxy = new HttpHost("3.211.17.212", 80);
// RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
// request.setConfig(config);
//3.执行get请求,相当于在输入地址栏后敲回车键
response = httpClient.execute(request);
//4.判断响应状态为200,进行处理
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//5.获取响应内容
HttpEntity httpEntity = response.getEntity();
html = EntityUtils.toString(httpEntity, "utf-8");
logger.info("访问{} 成功,返回页面数据{}", uri, html);
} else {
//如果返回状态不是200,比如404(页面不存在)等,根据情况做处理,这里略
logger.info("访问{},返回状态不是200", uri);
logger.info(EntityUtils.toString(response.getEntity(), "utf-8"));
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//6.关闭
HttpClientUtils.closeQuietly(response);
HttpClientUtils.closeQuietly(httpClient);
}
return html;
}
private void jsoupProcess(String html) {
Document document = Jsoup.parse(html);
Element price = document.getElementById("price9");
logger.info("股价为:>>> {}", price.text());
}
}
运行结果:
纳尼,股价是“-”?不可能的。
无法爬取正确结果的原因是因为这个值是在网站上异步加载渲染的,所以无法正常获取。
2.爬取异步加载数据的java方法
如何爬取异步加载的数据?通常有两种方法:
2.1 内置浏览器内核
内置浏览器就是在爬虫程序中启动一个浏览器内核,让js渲染出来的页面和静态页面一样。常用的内核有
这里我选择了 Selenium,它是一个模拟浏览器和自动化测试工具。它提供了一组 API 来与真正的浏览器内核交互。当然,爬虫也可以使用它。
具体方法如下:
2.2 逆向分析
反向解析的方法是通过F12找到Ajax异步数据获取的链接,直接调用链接得到json结果,然后直接解析json结果得到想要的数据。
此方法的关键是找到 Ajax 链接。这个方法我没研究过,有兴趣可以百度下载。稍微在这里。
3.结束语
以上就是如何通过selenium-java爬取异步加载的数据。通过这个方法,我写了一个小工具:
仓位市值通知系统,他每天会根据自己的仓位配置自动计算账户总市值,并发送邮件通知到指定邮箱。
使用的技术如下:
相关代码已经上传到我的码云,有兴趣的可以看看。 查看全部
java爬虫抓取动态网页(即为如何通过selenium-java爬取异步加载的数据的方法)
在之前的系列文章中介绍了如何使用httpclient抓取页面html以及如何使用jsoup分析html源文件的内容得到我们想要的数据,但是有时候这两种方法都不能使用捕获我们想要的数据。所需数据,例如,请参见以下示例。
1.需求场景:
如果要抢到股票的最新价格,F12页信息如下:

按照前面的方法,爬取的代码如下:
/**
* @description: 爬取股票的最新股价
* @author: JAVA开发老菜鸟
* @date: 2021-10-16 21:47
*/
public class StockPriceSpider {
Logger logger = LoggerFactory.getLogger(this.getClass());
public static void main(String[] args) {
StockPriceSpider stockPriceSpider = new StockPriceSpider();
String html = stockPriceSpider.httpClientProcess();
stockPriceSpider.jsoupProcess(html);
}
private String httpClientProcess() {
String html = "";
String uri = "http://quote.eastmoney.com/sh600036.html";
//1.生成httpclient,相当于该打开一个浏览器
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
//2.创建get请求,相当于在浏览器地址栏输入 网址
HttpGet request = new HttpGet(uri);
try {
request.setHeader("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36");
request.setHeader("accept", "application/json, text/javascript, */*; q=0.01");
// HttpHost proxy = new HttpHost("3.211.17.212", 80);
// RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
// request.setConfig(config);
//3.执行get请求,相当于在输入地址栏后敲回车键
response = httpClient.execute(request);
//4.判断响应状态为200,进行处理
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//5.获取响应内容
HttpEntity httpEntity = response.getEntity();
html = EntityUtils.toString(httpEntity, "utf-8");
logger.info("访问{} 成功,返回页面数据{}", uri, html);
} else {
//如果返回状态不是200,比如404(页面不存在)等,根据情况做处理,这里略
logger.info("访问{},返回状态不是200", uri);
logger.info(EntityUtils.toString(response.getEntity(), "utf-8"));
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//6.关闭
HttpClientUtils.closeQuietly(response);
HttpClientUtils.closeQuietly(httpClient);
}
return html;
}
private void jsoupProcess(String html) {
Document document = Jsoup.parse(html);
Element price = document.getElementById("price9");
logger.info("股价为:>>> {}", price.text());
}
}
运行结果:

纳尼,股价是“-”?不可能的。
无法爬取正确结果的原因是因为这个值是在网站上异步加载渲染的,所以无法正常获取。
2.爬取异步加载数据的java方法
如何爬取异步加载的数据?通常有两种方法:
2.1 内置浏览器内核
内置浏览器就是在爬虫程序中启动一个浏览器内核,让js渲染出来的页面和静态页面一样。常用的内核有
这里我选择了 Selenium,它是一个模拟浏览器和自动化测试工具。它提供了一组 API 来与真正的浏览器内核交互。当然,爬虫也可以使用它。
具体方法如下:
2.2 逆向分析
反向解析的方法是通过F12找到Ajax异步数据获取的链接,直接调用链接得到json结果,然后直接解析json结果得到想要的数据。
此方法的关键是找到 Ajax 链接。这个方法我没研究过,有兴趣可以百度下载。稍微在这里。
3.结束语
以上就是如何通过selenium-java爬取异步加载的数据。通过这个方法,我写了一个小工具:
仓位市值通知系统,他每天会根据自己的仓位配置自动计算账户总市值,并发送邮件通知到指定邮箱。
使用的技术如下:
相关代码已经上传到我的码云,有兴趣的可以看看。
java爬虫抓取动态网页(Web网络爬虫系统的功能及应用)
网站优化 • 优采云 发表了文章 • 0 个评论 • 48 次浏览 • 2022-02-02 05:01
1、爬虫技术概述
网络爬虫是根据一定的规则自动从万维网上爬取信息的程序或脚本。广泛应用于互联网搜索引擎或其他类似的网站,它可以自动采集它可以访问的页面的所有内容来获取或更新这些网站@的内容和检索方式>。从功能上来说,爬虫一般分为数据采集、处理、存储三部分。
传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在抓取网页的过程中,它不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。焦点爬虫的工作流程比较复杂。它需要按照一定的网页分析算法过滤掉与主题无关的链接,保留有用的链接,并放入等待抓取的URL队列中。然后,它会根据一定的搜索策略从队列中选择下一个要爬取的网页URL,并重复上述过程,直到达到系统的一定条件并停止。另外,爬虫爬取的所有网页都会被系统存储,进行一定的分析、过滤、索引,以供后续查询和检索;对于重点爬虫来说,这个过程中得到的分析结果也可能对后续的爬取过程给出反馈和指导。
与通用网络爬虫相比,聚焦爬虫还需要解决三个主要问题:
(1) 获取目标的描述或定义;
(2) 网页或数据的分析和过滤;
(3) URL 的搜索策略。
2、爬虫原理
2.1 网络爬虫原理
网络爬虫系统的功能是下载网页数据,为搜索引擎系统提供数据源。许多大型网络搜索引擎系统被称为基于Web数据的搜索引擎系统采集,如Google、百度等。这显示了网络爬虫系统在搜索引擎中的重要性。除了供用户阅读的文字信息外,网页还收录一些超链接信息。网络爬虫系统通过网页中的超链接信息不断获取网络上的其他网页。正是因为这个采集进程像爬虫或者蜘蛛一样在网络上漫游,所以才叫做网络爬虫系统或者网络蜘蛛系统,英文叫Spider或者Crawler。
2.2 网络爬虫系统的工作原理
在网络爬虫的系统框架中,主要流程由控制器、解析器和资源库三部分组成。控制器的主要工作是为多个线程中的每个爬虫线程分配工作任务。解析器的主要工作是下载网页和处理页面,主要是处理一些JS脚本标签、CSS代码内容、空格字符、HTML标签等。爬虫的基本工作是由解析器完成的。资源库用于存储下载的网络资源。通常使用大型数据库,例如 Oracle 数据库来存储和索引它。
控制器
控制器是网络爬虫的第一个控制器。主要负责根据系统发送的URL链接分配线程,然后启动线程调用爬虫爬取网页。
解析器
解析器负责网络爬虫的主要部分。它的主要任务是:下载网页的功能,处理网页的文本,如过滤,提取特殊的HTML标签,分析数据。
资源库
它主要是一个容器,用于存储从网页下载的数据记录,并为索引生成提供目标源。大中型数据库产品包括:Oracle、Sql Server等。
网络爬虫系统一般会选择一些比较重要的出度(网页中超链接数)网站较大的URL作为种子URL集。网络爬虫系统使用这些种子集作为初始 URL 来开始数据爬取。因为网页中收录链接信息,所以会通过已有网页的URL获取一些新的URL。网页之间的指向结构可以看作是一片森林。每个种子 URL 对应的网页是森林中一棵树的根节点。. 这样,网络爬虫系统就可以按照广度优先算法或深度优先算法遍历所有网页。由于深度优先搜索算法可能导致爬虫系统陷入网站内部,不利于搜索距离网站首页比较近的网页信息,一般采用广度优先搜索算法采集网页。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。
网络爬虫的基本工作流程如下:
1.首先选择一个精心挑选的种子 URL 的子集;
2.将这些网址放入待抓取的网址队列中;
3. 从待爬取URL队列中取出待爬取的URL,解析DNS,获取主机IP,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URLs 队列;
4.分析已经爬取的URL队列中的URL,分析其中的其他URL,将这些URL放入待爬取的URL队列,从而进入下一个循环。
2.3 爬取策略
在爬虫系统中,待爬取的 URL 队列是一个重要的部分。待爬取的URL队列中的URL的排列顺序也是一个重要的问题,因为它涉及到先爬到哪个页面,再爬到哪个页面。确定这些 URL 排列顺序的方法称为爬取策略。下面重点介绍几种常见的爬取策略:
2.3.1 深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,每次一个链接跟踪每个链接,处理完该行后移动到下一个起始页,并继续跟踪该链接。我们以下图为例:
遍历的路径:AFG EHI BCD
2.3.2 广度优先遍历策略
广度优先遍历策略的基本思想是将新下载的网页中找到的链接直接放到待爬取的URL队列的末尾。也就是说,网络爬虫会先爬取起始网页链接的所有网页,然后选择其中一个链接的网页,继续爬取该网页链接的所有网页。或者以上图为例:
遍历路径:ABCDEF GHI
2.3.3 反向链接策略
反向链接数是指从其他网页指向一个网页的链接数。反向链接的数量表示网页内容被他人推荐的程度。因此,在很多情况下,搜索引擎的爬取系统会使用这个指标来评估网页的重要性,从而确定不同网页的爬取顺序。
在真实的网络环境中,由于广告链接和作弊链接的存在,反向链接的数量并不能完全等同于他人的重要性。因此,搜索引擎倾向于考虑一些可靠的反向链接计数。
2.3.4 部分PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于下载的网页,与待爬取的URL队列中的URL一起,形成一组网页,计算每个页面的PageRank值. URL 按 PageRank 值排序,并按该顺序抓取页面。
如果每次爬取一个页面都重新计算一次PageRank值,折中的解决方案是:每爬完K个页面,重新计算一次PageRank值。但是这种情况还是有一个问题:对于下载页面中分析的链接,也就是我们前面提到的未知网页部分,暂时没有PageRank值。为了解决这个问题,会给这些页面一个临时的PageRank值:将这个网页所有传入链接传入的PageRank值聚合起来,从而形成未知页面的PageRank值,从而参与排序。
2.3.5 OPIC 政策方针
该算法实际上为页面分配了一个重要性分数。在算法开始之前,所有页面都会获得相同的初始现金。当某个页面P被下载时,P的现金分配给从P分析的所有链接,P的现金被清空。根据现金数量对待爬取URL队列中的所有页面进行排序。
2.3.6 大网站优先策略
所有待爬取的URL队列中的网页都按照它们所属的网站进行分类。网站需要下载的页面较多,请先下载。这种策略也称为大站点优先策略。
3、爬虫分类
我应该选择 Nutch、Crawler4j、WebMagic、scrapy、WebCollector 还是其他来开发网络爬虫?上面提到的爬虫类,基本上可以分为三类:
(1)分布式爬虫:Nutch
(2)JAVA 爬虫:Crawler4j、WebMagic、WebCollector
(3)非JAVA爬虫:scrapy(基于Python语言开发)
3.1 分布式爬虫
爬虫使用分布式,主要解决两个问题:
1)海量网址管理
2)网速
现在比较流行的分布式爬虫是Apache的Nutch。但是对于大多数用户来说,Nutch 是这些爬虫中最差的选择,原因如下:
1)Nutch 是为搜索引擎设计的爬虫。大多数用户需要一个爬虫来进行准确的数据爬取(精细提取)。Nutch 运行的三分之二的流程是为搜索引擎设计的。提取意义不大。换句话说,使用 Nutch 进行数据提取会在不必要的计算上浪费大量时间。而如果你试图通过Nutch的二次开发使其适合提取业务,你基本上会破坏Nutch的框架,将Nutch改得面目全非,并且有能力修改Nutch,还不如自己写一个新的. 分布式爬虫框架。
2)Nutch 依赖hadoop 运行,hadoop 本身消耗大量时间。如果集群机器数量少,爬取速度不如单机爬虫快。
3)虽然Nutch有一套插件机制,但还是作为亮点来宣传的。可以看到一些开源的Nutch插件,提供精准提取功能。但是任何开发过 Nutch 插件的人都知道 Nutch 的插件系统有多糟糕。使用反射机制加载和调用插件,使得程序的编写和调试变得异常困难,更不用说在其上开发复杂的提取系统了。并且 Nutch 没有提供对应的插件挂载点进行精细提取。Nutch的插件只有五六个挂载点,而这五六个挂载点都是给搜索引擎服务的,不提供细提取的挂载点。Nutch 的大部分精炼提取插件都安装在“解析器”安装点上。这个挂载点其实是用来解析链接(为后续爬取提供URL)和提供一些搜索引擎的。易于提取的网页信息(元信息、网页文本)。
4)使用Nutch进行爬虫的二次开发,编写和调试爬虫所需的时间往往是单机爬虫所需时间的十倍以上。学习 Nutch 源码的成本非常高,更何况团队中的每个人都必须了解 Nutch 源码。在调试过程中,会出现程序本身以外的各种问题(hadoop问题、hbase问题)。
5)很多人说Nutch2有gora,可以将数据持久化到avro文件、hbase、mysql等,其实很多人理解错了。这里所说的持久化数据是指在avro、hbase、mysql中存储URL信息(URL管理所需的数据)。不是您要提取的结构化数据。事实上,对于大多数人来说,URL 信息存在于何处并不重要。
6)Nutch2 的版本目前不适合开发。Nutch的官方稳定版是nutch2.2.1,但是这个版本绑定了gora-0.3。如果要使用hbase和nutch(大多数人使用nutch2是为了使用hbase),只能使用版本0.90左右的hbase,相应地,将hadoop版本降低到hadoop 0.左右@>2。而且nutch2的官方教程也颇具误导性。Nutch2的教程有两个,分别是Nutch1.x和Nutch2.x。这个Nutch2.x官网是为了支持hbase0.94而写的。但其实这个Nutch2.x是指Nutch2.3之前和Nutch2.2.1之后的一个版本,在官方SVN中不断更新。而且它'
所以,如果你不是搜索引擎,尽量不要选择 Nutch 作为爬虫。一些团队喜欢跟风。他们坚持选择Nutch来开发精制履带。事实上,这是针对Nutch的声誉。当然,最终的结果往往是项目延期。
如果你在做搜索引擎,Nutch1.x 是一个非常不错的选择。Nutch1.x 和 solr 或 es 可以组成一个非常强大的搜索引擎。如果必须使用 Nutch2,建议等到 Nutch2.3 发布。当前的 Nutch2 是一个非常不稳定的版本。
3.2 JAVA爬虫
在这里,将JAVA爬虫划分为一个单独的类别,因为JAVA在网络爬虫的生态系统中非常完善。相关资料也是最全的。这里可能有争议,我只是随便说说。
其实开源网络爬虫(框架)的开发很简单,难点和复杂的问题已经被前人解决了(比如DOM树解析定位、字符集检测、海量URL去重),可以说没有技术含量。包括Nutch,其实Nutch的技术难点就是开发hadoop,代码本身也很简单。从某种意义上说,网络爬虫类似于遍历本机的文件以查找文件中的信息。没有任何困难。选择开源爬虫框架的原因是为了省事。比如爬虫的URL管理、线程池等模块,任何人都可以做,但是需要一段时间的调试和修改才能稳定下来。
对于爬虫的功能。用户比较关心的问题往往是:
1)爬虫是否支持多线程,爬虫是否可以使用代理,爬虫是否可以爬取重复数据,爬虫是否可以爬取JS生成的信息?
不支持多线程、不支持代理、不能过滤重复URL的不叫开源爬虫,叫循环执行http请求。
js生成的信息能否被爬取与爬虫本身关系不大。爬虫主要负责遍历网站和下载页面。爬取js产生的信息与网页信息提取模块有关,往往需要通过模拟浏览器(htmlunit、selenium)来完成。这些模拟浏览器通常需要花费大量时间来处理一个页面。因此,一种策略是利用这些爬虫遍历网站,当遇到需要解析的页面时,将网页的相关信息提交给模拟浏览器,完成对JS生成信息的提取。
2)爬虫可以抓取ajax信息吗?
网页上有一些异步加载的数据。爬取数据有两种方式:使用模拟浏览器(问题1中描述),或者分析ajax的http请求,自己生成ajax请求的url,获取返回的数据。如果你自己生成ajax请求,那么使用开源爬虫有什么意义呢?其实就是利用开源爬虫的线程池和URL管理功能(比如断点爬取)。
如果我已经可以生成我需要的ajax请求(列表),我该如何使用这些爬虫来爬取这些请求呢?
爬虫往往被设计成广度遍历或深度遍历的方式来遍历静态或动态页面。爬取ajax信息属于深网(deep web)的范畴,虽然大部分爬虫并不直接支持。但它也可以通过某些方式完成。例如,WebCollector 使用广度遍历来遍历 网站。爬虫的第一轮爬取就是爬取种子集(seeds)中的所有url。简单来说就是将生成的ajax请求作为种子,放入爬虫中。使用爬虫对这些种子进行深度为 1 的广度遍历(默认为广度遍历)。
3)爬虫如何爬取待登录的网站?
这些开源爬虫都支持在爬取时指定cookies,而模拟登录主要依赖cookies。至于如何获取cookies,就不是爬虫管理的问题了。您可以手动获取cookies,使用http请求模拟登录,或者使用模拟浏览器自动登录。
4)爬虫如何从网页中提取信息?
开源爬虫一般会集成网页提取工具。主要支持两种规范:CSS SELECTOR 和 XPATH。至于哪个更好,我这里就不评论了。
5)爬虫是如何保存网页信息的?
有一些爬虫带有一个负责持久性的模块。例如,webmagic 有一个名为 pipeline 的模块。通过简单的配置,爬虫提取的信息可以持久化到文件、数据库等。还有一些爬虫不直接为用户提供数据持久化模块。比如 crawler4j 和 webcollector。让用户在网页处理模块中添加提交数据库的操作。至于用管道模块好不好,就类似于用ORM操作数据库好不好的问题,看你的业务。
6)爬虫被网站拦截了怎么办?
爬虫被网站阻塞,通常可以通过使用多个代理(随机代理)来解决。但是这些开源爬虫一般不直接支持随机代理的切换。因此,用户经常需要将获取到的代理放入一个全局数组中,并编写代码让代理随机获取(从数组中)。
7)网页可以调用爬虫吗?
爬虫的调用是在Web的服务器端调用的。您可以按照平时使用的方式使用它。可以使用这些爬虫。
8)爬虫速度怎么样?
单机开源爬虫的速度基本可以用到本地网速的极限。爬虫速度慢往往是因为用户减少了线程数,网速慢,或者数据持久化时与数据库的交互慢。而这些东西往往是由用户的机器和二次开发的代码决定的。这些开源爬虫的速度非常好。
9) 明明代码写对了,但是数据爬不出来。爬虫有问题吗?另一个爬虫可以解决吗?
如果代码写得正确,无法爬取数据,其他爬虫也将无法爬取。在这种情况下,要么是 网站 阻止了您,要么您抓取的数据是由 javascript 生成的。如果无法爬取数据,则无法通过更改爬虫来解决。
10)哪个爬虫可以判断网站是否已经爬完,哪个爬虫可以根据主题爬取?
爬虫无法判断网站是否已经爬完,只能尽量覆盖。
至于根据主题爬,爬虫把内容爬下来后就知道主题是什么了。因此,通常是整体爬下来,然后对内容进行过滤。如果爬取的范围太广,可以通过限制 URL 正则化来缩小范围。
11)哪个爬虫的设计模式和架构比较好?
设计模式是胡说八道。都说软件设计模式不错,软件开发后总结了几种设计模式。设计模式对软件开发没有指导意义。使用设计模式设计爬虫只会让爬虫的设计更加臃肿。
至于架构,目前开源爬虫主要是设计详细的数据结构,比如爬取线程池、任务队列等,大家都可以控制。爬虫的业务太简单了,用任何框架都谈不上。
所以对于 JAVA 开源爬虫,我认为,只要找到一个运行良好的。如果业务复杂,使用哪个爬虫,只能通过复杂的二次开发来满足需求。
3.3 非JAVA爬虫
在非JAVA语言编写的爬虫中,不乏优秀的爬虫。这里提取为一个类别,不是为了讨论爬虫本身的好坏,而是为了讨论larbin、scrapy等爬虫对开发成本的影响。
先说python爬虫,python用30行代码就可以完成JAVA 50行代码的任务。Python写代码确实很快,但是在调试代码阶段,调试python代码所消耗的时间往往比编码阶段节省的时间要多得多。使用python开发,为了保证程序的正确性和稳定性,需要编写更多的测试模块。当然,如果爬取规模不大,爬取业务也不复杂,用scrapy还是不错的,可以轻松完成爬取任务。
上图是Scrapy的架构图。绿线是数据流。从初始 URL 开始,Scheduler 会将其交给 Downloader 进行下载。下载完成后交给 Spider 进行分析,将要保存的数据发送到 Item Pipeline ,也就是对数据进行后处理。此外,可以在数据流通道中安装各种中间件,进行必要的处理。因此,在开发爬虫时,最好先规划好各个模块。我的做法是分别规划下载模块、爬取模块、调度模块、数据存储模块。
对于C++爬虫来说,学习**的成本会比较大。而且你不能只计算一个人的学习成本。如果软件需要一个团队来开发或交接,那是很多人学习的成本。软件调试不是那么容易。
还有一些ruby和php爬虫,这里就不多评价了。确实有一些非常小的data采集任务,在ruby或者php中都用得上。但是,要选择这些语言的开源爬虫,一方面需要调查相关的生态系统,另一方面,这些开源爬虫可能存在一些你找不到的bug(很少有人使用它们,和更少的信息)。
4、反爬虫技术
由于搜索引擎的普及,网络爬虫已经成为一种非常流行的网络技术。除了专注于搜索的谷歌、雅虎、微软和百度,几乎每个大型门户网站网站都有自己的搜索引擎。有几十个名字和成千上万个未知的名字。对于内容驱动的网站,网络爬虫的赞助是不可避免的。
一些智能搜索引擎爬虫的爬取频率比较合理,资源消耗也比较小,但是很多不良网络爬虫对网页的爬取能力很差,经常循环重复上百个请求。拿,这种爬虫对中小型网站来说往往是毁灭性的打击,尤其是一些缺乏爬虫编写经验的程序员编写的爬虫,破坏性极大,导致网站访问压力会很大非常大,这将导致 网站 访问缓慢甚至无法访问。
一般网站反爬虫从三个方面:用户请求的头文件、用户行为、网站目录和数据加载方式。前两种比较容易遇到,从这些角度来看,大部分网站都是反爬虫。会使用第三种使用ajax的网站,增加了爬取的难度。
4.1 反爬虫通过Headers
反爬取用户请求的头部是最常见的反爬取策略。很多网站会检测Headers的User-Agent,有的网站会检测Referer(有些资源的防盗链网站就是检测Referer)。如果遇到这样的反爬虫机制,可以直接在爬虫中添加Headers,将浏览器的User-Agent复制到爬虫的Headers中;或者将Referer值改为目标网站域名。对于检测Headers的反爬虫,在爬虫中修改或添加Headers可以很好的绕过。
[评论:它经常很容易被忽视。通过对请求的抓包分析,确定referer并添加到程序中模拟访问请求的header中]
4.2 基于用户行为的反爬虫
网站的另一部分是检测用户行为,比如同一个IP在短时间内多次访问同一个页面,或者同一个账号在短时间内多次执行相同的操作。
喜欢
不喜欢
你对这个答案的评价是什么? 查看全部
java爬虫抓取动态网页(Web网络爬虫系统的功能及应用)
1、爬虫技术概述
网络爬虫是根据一定的规则自动从万维网上爬取信息的程序或脚本。广泛应用于互联网搜索引擎或其他类似的网站,它可以自动采集它可以访问的页面的所有内容来获取或更新这些网站@的内容和检索方式>。从功能上来说,爬虫一般分为数据采集、处理、存储三部分。
传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在抓取网页的过程中,它不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。焦点爬虫的工作流程比较复杂。它需要按照一定的网页分析算法过滤掉与主题无关的链接,保留有用的链接,并放入等待抓取的URL队列中。然后,它会根据一定的搜索策略从队列中选择下一个要爬取的网页URL,并重复上述过程,直到达到系统的一定条件并停止。另外,爬虫爬取的所有网页都会被系统存储,进行一定的分析、过滤、索引,以供后续查询和检索;对于重点爬虫来说,这个过程中得到的分析结果也可能对后续的爬取过程给出反馈和指导。
与通用网络爬虫相比,聚焦爬虫还需要解决三个主要问题:
(1) 获取目标的描述或定义;
(2) 网页或数据的分析和过滤;
(3) URL 的搜索策略。
2、爬虫原理
2.1 网络爬虫原理
网络爬虫系统的功能是下载网页数据,为搜索引擎系统提供数据源。许多大型网络搜索引擎系统被称为基于Web数据的搜索引擎系统采集,如Google、百度等。这显示了网络爬虫系统在搜索引擎中的重要性。除了供用户阅读的文字信息外,网页还收录一些超链接信息。网络爬虫系统通过网页中的超链接信息不断获取网络上的其他网页。正是因为这个采集进程像爬虫或者蜘蛛一样在网络上漫游,所以才叫做网络爬虫系统或者网络蜘蛛系统,英文叫Spider或者Crawler。
2.2 网络爬虫系统的工作原理
在网络爬虫的系统框架中,主要流程由控制器、解析器和资源库三部分组成。控制器的主要工作是为多个线程中的每个爬虫线程分配工作任务。解析器的主要工作是下载网页和处理页面,主要是处理一些JS脚本标签、CSS代码内容、空格字符、HTML标签等。爬虫的基本工作是由解析器完成的。资源库用于存储下载的网络资源。通常使用大型数据库,例如 Oracle 数据库来存储和索引它。
控制器
控制器是网络爬虫的第一个控制器。主要负责根据系统发送的URL链接分配线程,然后启动线程调用爬虫爬取网页。
解析器
解析器负责网络爬虫的主要部分。它的主要任务是:下载网页的功能,处理网页的文本,如过滤,提取特殊的HTML标签,分析数据。
资源库
它主要是一个容器,用于存储从网页下载的数据记录,并为索引生成提供目标源。大中型数据库产品包括:Oracle、Sql Server等。
网络爬虫系统一般会选择一些比较重要的出度(网页中超链接数)网站较大的URL作为种子URL集。网络爬虫系统使用这些种子集作为初始 URL 来开始数据爬取。因为网页中收录链接信息,所以会通过已有网页的URL获取一些新的URL。网页之间的指向结构可以看作是一片森林。每个种子 URL 对应的网页是森林中一棵树的根节点。. 这样,网络爬虫系统就可以按照广度优先算法或深度优先算法遍历所有网页。由于深度优先搜索算法可能导致爬虫系统陷入网站内部,不利于搜索距离网站首页比较近的网页信息,一般采用广度优先搜索算法采集网页。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。网络爬虫系统首先将种子 URL 放入下载队列,然后简单地从队列头部获取一个 URL 来下载其对应的网页。获取网页内容并存储后,通过解析网页中的链接信息可以得到一些新的URL,并将这些URL加入到下载队列中。然后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。
网络爬虫的基本工作流程如下:
1.首先选择一个精心挑选的种子 URL 的子集;
2.将这些网址放入待抓取的网址队列中;
3. 从待爬取URL队列中取出待爬取的URL,解析DNS,获取主机IP,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URLs 队列;
4.分析已经爬取的URL队列中的URL,分析其中的其他URL,将这些URL放入待爬取的URL队列,从而进入下一个循环。
2.3 爬取策略
在爬虫系统中,待爬取的 URL 队列是一个重要的部分。待爬取的URL队列中的URL的排列顺序也是一个重要的问题,因为它涉及到先爬到哪个页面,再爬到哪个页面。确定这些 URL 排列顺序的方法称为爬取策略。下面重点介绍几种常见的爬取策略:
2.3.1 深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,每次一个链接跟踪每个链接,处理完该行后移动到下一个起始页,并继续跟踪该链接。我们以下图为例:
遍历的路径:AFG EHI BCD
2.3.2 广度优先遍历策略
广度优先遍历策略的基本思想是将新下载的网页中找到的链接直接放到待爬取的URL队列的末尾。也就是说,网络爬虫会先爬取起始网页链接的所有网页,然后选择其中一个链接的网页,继续爬取该网页链接的所有网页。或者以上图为例:
遍历路径:ABCDEF GHI
2.3.3 反向链接策略
反向链接数是指从其他网页指向一个网页的链接数。反向链接的数量表示网页内容被他人推荐的程度。因此,在很多情况下,搜索引擎的爬取系统会使用这个指标来评估网页的重要性,从而确定不同网页的爬取顺序。
在真实的网络环境中,由于广告链接和作弊链接的存在,反向链接的数量并不能完全等同于他人的重要性。因此,搜索引擎倾向于考虑一些可靠的反向链接计数。
2.3.4 部分PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于下载的网页,与待爬取的URL队列中的URL一起,形成一组网页,计算每个页面的PageRank值. URL 按 PageRank 值排序,并按该顺序抓取页面。
如果每次爬取一个页面都重新计算一次PageRank值,折中的解决方案是:每爬完K个页面,重新计算一次PageRank值。但是这种情况还是有一个问题:对于下载页面中分析的链接,也就是我们前面提到的未知网页部分,暂时没有PageRank值。为了解决这个问题,会给这些页面一个临时的PageRank值:将这个网页所有传入链接传入的PageRank值聚合起来,从而形成未知页面的PageRank值,从而参与排序。
2.3.5 OPIC 政策方针
该算法实际上为页面分配了一个重要性分数。在算法开始之前,所有页面都会获得相同的初始现金。当某个页面P被下载时,P的现金分配给从P分析的所有链接,P的现金被清空。根据现金数量对待爬取URL队列中的所有页面进行排序。
2.3.6 大网站优先策略
所有待爬取的URL队列中的网页都按照它们所属的网站进行分类。网站需要下载的页面较多,请先下载。这种策略也称为大站点优先策略。
3、爬虫分类
我应该选择 Nutch、Crawler4j、WebMagic、scrapy、WebCollector 还是其他来开发网络爬虫?上面提到的爬虫类,基本上可以分为三类:
(1)分布式爬虫:Nutch
(2)JAVA 爬虫:Crawler4j、WebMagic、WebCollector
(3)非JAVA爬虫:scrapy(基于Python语言开发)
3.1 分布式爬虫
爬虫使用分布式,主要解决两个问题:
1)海量网址管理
2)网速
现在比较流行的分布式爬虫是Apache的Nutch。但是对于大多数用户来说,Nutch 是这些爬虫中最差的选择,原因如下:
1)Nutch 是为搜索引擎设计的爬虫。大多数用户需要一个爬虫来进行准确的数据爬取(精细提取)。Nutch 运行的三分之二的流程是为搜索引擎设计的。提取意义不大。换句话说,使用 Nutch 进行数据提取会在不必要的计算上浪费大量时间。而如果你试图通过Nutch的二次开发使其适合提取业务,你基本上会破坏Nutch的框架,将Nutch改得面目全非,并且有能力修改Nutch,还不如自己写一个新的. 分布式爬虫框架。
2)Nutch 依赖hadoop 运行,hadoop 本身消耗大量时间。如果集群机器数量少,爬取速度不如单机爬虫快。
3)虽然Nutch有一套插件机制,但还是作为亮点来宣传的。可以看到一些开源的Nutch插件,提供精准提取功能。但是任何开发过 Nutch 插件的人都知道 Nutch 的插件系统有多糟糕。使用反射机制加载和调用插件,使得程序的编写和调试变得异常困难,更不用说在其上开发复杂的提取系统了。并且 Nutch 没有提供对应的插件挂载点进行精细提取。Nutch的插件只有五六个挂载点,而这五六个挂载点都是给搜索引擎服务的,不提供细提取的挂载点。Nutch 的大部分精炼提取插件都安装在“解析器”安装点上。这个挂载点其实是用来解析链接(为后续爬取提供URL)和提供一些搜索引擎的。易于提取的网页信息(元信息、网页文本)。
4)使用Nutch进行爬虫的二次开发,编写和调试爬虫所需的时间往往是单机爬虫所需时间的十倍以上。学习 Nutch 源码的成本非常高,更何况团队中的每个人都必须了解 Nutch 源码。在调试过程中,会出现程序本身以外的各种问题(hadoop问题、hbase问题)。
5)很多人说Nutch2有gora,可以将数据持久化到avro文件、hbase、mysql等,其实很多人理解错了。这里所说的持久化数据是指在avro、hbase、mysql中存储URL信息(URL管理所需的数据)。不是您要提取的结构化数据。事实上,对于大多数人来说,URL 信息存在于何处并不重要。
6)Nutch2 的版本目前不适合开发。Nutch的官方稳定版是nutch2.2.1,但是这个版本绑定了gora-0.3。如果要使用hbase和nutch(大多数人使用nutch2是为了使用hbase),只能使用版本0.90左右的hbase,相应地,将hadoop版本降低到hadoop 0.左右@>2。而且nutch2的官方教程也颇具误导性。Nutch2的教程有两个,分别是Nutch1.x和Nutch2.x。这个Nutch2.x官网是为了支持hbase0.94而写的。但其实这个Nutch2.x是指Nutch2.3之前和Nutch2.2.1之后的一个版本,在官方SVN中不断更新。而且它'
所以,如果你不是搜索引擎,尽量不要选择 Nutch 作为爬虫。一些团队喜欢跟风。他们坚持选择Nutch来开发精制履带。事实上,这是针对Nutch的声誉。当然,最终的结果往往是项目延期。
如果你在做搜索引擎,Nutch1.x 是一个非常不错的选择。Nutch1.x 和 solr 或 es 可以组成一个非常强大的搜索引擎。如果必须使用 Nutch2,建议等到 Nutch2.3 发布。当前的 Nutch2 是一个非常不稳定的版本。
3.2 JAVA爬虫
在这里,将JAVA爬虫划分为一个单独的类别,因为JAVA在网络爬虫的生态系统中非常完善。相关资料也是最全的。这里可能有争议,我只是随便说说。
其实开源网络爬虫(框架)的开发很简单,难点和复杂的问题已经被前人解决了(比如DOM树解析定位、字符集检测、海量URL去重),可以说没有技术含量。包括Nutch,其实Nutch的技术难点就是开发hadoop,代码本身也很简单。从某种意义上说,网络爬虫类似于遍历本机的文件以查找文件中的信息。没有任何困难。选择开源爬虫框架的原因是为了省事。比如爬虫的URL管理、线程池等模块,任何人都可以做,但是需要一段时间的调试和修改才能稳定下来。
对于爬虫的功能。用户比较关心的问题往往是:
1)爬虫是否支持多线程,爬虫是否可以使用代理,爬虫是否可以爬取重复数据,爬虫是否可以爬取JS生成的信息?
不支持多线程、不支持代理、不能过滤重复URL的不叫开源爬虫,叫循环执行http请求。
js生成的信息能否被爬取与爬虫本身关系不大。爬虫主要负责遍历网站和下载页面。爬取js产生的信息与网页信息提取模块有关,往往需要通过模拟浏览器(htmlunit、selenium)来完成。这些模拟浏览器通常需要花费大量时间来处理一个页面。因此,一种策略是利用这些爬虫遍历网站,当遇到需要解析的页面时,将网页的相关信息提交给模拟浏览器,完成对JS生成信息的提取。
2)爬虫可以抓取ajax信息吗?
网页上有一些异步加载的数据。爬取数据有两种方式:使用模拟浏览器(问题1中描述),或者分析ajax的http请求,自己生成ajax请求的url,获取返回的数据。如果你自己生成ajax请求,那么使用开源爬虫有什么意义呢?其实就是利用开源爬虫的线程池和URL管理功能(比如断点爬取)。
如果我已经可以生成我需要的ajax请求(列表),我该如何使用这些爬虫来爬取这些请求呢?
爬虫往往被设计成广度遍历或深度遍历的方式来遍历静态或动态页面。爬取ajax信息属于深网(deep web)的范畴,虽然大部分爬虫并不直接支持。但它也可以通过某些方式完成。例如,WebCollector 使用广度遍历来遍历 网站。爬虫的第一轮爬取就是爬取种子集(seeds)中的所有url。简单来说就是将生成的ajax请求作为种子,放入爬虫中。使用爬虫对这些种子进行深度为 1 的广度遍历(默认为广度遍历)。
3)爬虫如何爬取待登录的网站?
这些开源爬虫都支持在爬取时指定cookies,而模拟登录主要依赖cookies。至于如何获取cookies,就不是爬虫管理的问题了。您可以手动获取cookies,使用http请求模拟登录,或者使用模拟浏览器自动登录。
4)爬虫如何从网页中提取信息?
开源爬虫一般会集成网页提取工具。主要支持两种规范:CSS SELECTOR 和 XPATH。至于哪个更好,我这里就不评论了。
5)爬虫是如何保存网页信息的?
有一些爬虫带有一个负责持久性的模块。例如,webmagic 有一个名为 pipeline 的模块。通过简单的配置,爬虫提取的信息可以持久化到文件、数据库等。还有一些爬虫不直接为用户提供数据持久化模块。比如 crawler4j 和 webcollector。让用户在网页处理模块中添加提交数据库的操作。至于用管道模块好不好,就类似于用ORM操作数据库好不好的问题,看你的业务。
6)爬虫被网站拦截了怎么办?
爬虫被网站阻塞,通常可以通过使用多个代理(随机代理)来解决。但是这些开源爬虫一般不直接支持随机代理的切换。因此,用户经常需要将获取到的代理放入一个全局数组中,并编写代码让代理随机获取(从数组中)。
7)网页可以调用爬虫吗?
爬虫的调用是在Web的服务器端调用的。您可以按照平时使用的方式使用它。可以使用这些爬虫。
8)爬虫速度怎么样?
单机开源爬虫的速度基本可以用到本地网速的极限。爬虫速度慢往往是因为用户减少了线程数,网速慢,或者数据持久化时与数据库的交互慢。而这些东西往往是由用户的机器和二次开发的代码决定的。这些开源爬虫的速度非常好。
9) 明明代码写对了,但是数据爬不出来。爬虫有问题吗?另一个爬虫可以解决吗?
如果代码写得正确,无法爬取数据,其他爬虫也将无法爬取。在这种情况下,要么是 网站 阻止了您,要么您抓取的数据是由 javascript 生成的。如果无法爬取数据,则无法通过更改爬虫来解决。
10)哪个爬虫可以判断网站是否已经爬完,哪个爬虫可以根据主题爬取?
爬虫无法判断网站是否已经爬完,只能尽量覆盖。
至于根据主题爬,爬虫把内容爬下来后就知道主题是什么了。因此,通常是整体爬下来,然后对内容进行过滤。如果爬取的范围太广,可以通过限制 URL 正则化来缩小范围。
11)哪个爬虫的设计模式和架构比较好?
设计模式是胡说八道。都说软件设计模式不错,软件开发后总结了几种设计模式。设计模式对软件开发没有指导意义。使用设计模式设计爬虫只会让爬虫的设计更加臃肿。
至于架构,目前开源爬虫主要是设计详细的数据结构,比如爬取线程池、任务队列等,大家都可以控制。爬虫的业务太简单了,用任何框架都谈不上。
所以对于 JAVA 开源爬虫,我认为,只要找到一个运行良好的。如果业务复杂,使用哪个爬虫,只能通过复杂的二次开发来满足需求。
3.3 非JAVA爬虫
在非JAVA语言编写的爬虫中,不乏优秀的爬虫。这里提取为一个类别,不是为了讨论爬虫本身的好坏,而是为了讨论larbin、scrapy等爬虫对开发成本的影响。
先说python爬虫,python用30行代码就可以完成JAVA 50行代码的任务。Python写代码确实很快,但是在调试代码阶段,调试python代码所消耗的时间往往比编码阶段节省的时间要多得多。使用python开发,为了保证程序的正确性和稳定性,需要编写更多的测试模块。当然,如果爬取规模不大,爬取业务也不复杂,用scrapy还是不错的,可以轻松完成爬取任务。
上图是Scrapy的架构图。绿线是数据流。从初始 URL 开始,Scheduler 会将其交给 Downloader 进行下载。下载完成后交给 Spider 进行分析,将要保存的数据发送到 Item Pipeline ,也就是对数据进行后处理。此外,可以在数据流通道中安装各种中间件,进行必要的处理。因此,在开发爬虫时,最好先规划好各个模块。我的做法是分别规划下载模块、爬取模块、调度模块、数据存储模块。
对于C++爬虫来说,学习**的成本会比较大。而且你不能只计算一个人的学习成本。如果软件需要一个团队来开发或交接,那是很多人学习的成本。软件调试不是那么容易。
还有一些ruby和php爬虫,这里就不多评价了。确实有一些非常小的data采集任务,在ruby或者php中都用得上。但是,要选择这些语言的开源爬虫,一方面需要调查相关的生态系统,另一方面,这些开源爬虫可能存在一些你找不到的bug(很少有人使用它们,和更少的信息)。
4、反爬虫技术
由于搜索引擎的普及,网络爬虫已经成为一种非常流行的网络技术。除了专注于搜索的谷歌、雅虎、微软和百度,几乎每个大型门户网站网站都有自己的搜索引擎。有几十个名字和成千上万个未知的名字。对于内容驱动的网站,网络爬虫的赞助是不可避免的。
一些智能搜索引擎爬虫的爬取频率比较合理,资源消耗也比较小,但是很多不良网络爬虫对网页的爬取能力很差,经常循环重复上百个请求。拿,这种爬虫对中小型网站来说往往是毁灭性的打击,尤其是一些缺乏爬虫编写经验的程序员编写的爬虫,破坏性极大,导致网站访问压力会很大非常大,这将导致 网站 访问缓慢甚至无法访问。
一般网站反爬虫从三个方面:用户请求的头文件、用户行为、网站目录和数据加载方式。前两种比较容易遇到,从这些角度来看,大部分网站都是反爬虫。会使用第三种使用ajax的网站,增加了爬取的难度。
4.1 反爬虫通过Headers
反爬取用户请求的头部是最常见的反爬取策略。很多网站会检测Headers的User-Agent,有的网站会检测Referer(有些资源的防盗链网站就是检测Referer)。如果遇到这样的反爬虫机制,可以直接在爬虫中添加Headers,将浏览器的User-Agent复制到爬虫的Headers中;或者将Referer值改为目标网站域名。对于检测Headers的反爬虫,在爬虫中修改或添加Headers可以很好的绕过。
[评论:它经常很容易被忽视。通过对请求的抓包分析,确定referer并添加到程序中模拟访问请求的header中]
4.2 基于用户行为的反爬虫
网站的另一部分是检测用户行为,比如同一个IP在短时间内多次访问同一个页面,或者同一个账号在短时间内多次执行相同的操作。
喜欢
不喜欢
你对这个答案的评价是什么?
java爬虫抓取动态网页(之前第一篇教程.js爬虫入门(一)爬取静态页面)
网站优化 • 优采云 发表了文章 • 0 个评论 • 47 次浏览 • 2022-02-01 18:11
之前的第一篇爬虫教程,Node.js爬虫介绍(一)爬取静态页面讲解静态网页的爬取,很简单,但是如果遇到一些动态网页(ajax),可以直接用之前发送请求的方法我们都拿不到我们想要的数据,这时候需要爬取动态网页,selenium和puppeteer都不错。
这里推荐使用puppeteer,不为别的,只因为他是谷歌自己的,一直在维护更新。以下是翻译的官方文档介绍
Puppeteer 是一个 Node 库,提供一系列高级接口,通过 DevTools(开发者工具)协议控制 Chrome 或 Chromium(谷歌开源)。它默认以无头模式运行(无浏览器 UI),也可以通过配置以正常模式运行。
它可用于:
首先,我们必须在使用它之前安装它。默认安装会附带下载最新的 Chromium,大小约为 300M。
npm install puppeteer
如果本地已经有较新版本的chrome,可以只安装core版本,但是启动puppeteer时需要配置本地chrome的路径。
npm install puppeteer-core // 核心版本
假设我们现在要爬取拉狗网的前端招聘信息。这是一个动态页面。使用下面的示例尝试抓取。
因为chrome操作都是异步操作,为了避免回调地狱,推荐使用es7的async await。这种语法具有高度可读性,官方文档也是如此。
首先使用 puppeteer 启动浏览器并打开该动态页面
这里需要注意的是,如果使用的是本地浏览器,需要在启动浏览器配置中传入本地chrome路径
const browser = await puppeteer.launch({
executablePath: 'C:/Users/Administrator/AppData/Local/Google/Chrome/Application/chrome.exe'
})
在chrome环境中执行函数获取需要的数据然后返回节点的执行环境
上图是我们需要的数据的dom位置。在chrome环境执行的函数中,我们需要获取并整理需要的数据。
let list = document.querySelectorAll('.s_position_list .item_con_list li')
let res = []
for (let i = 0; i < list.length; i++) {
res.push({
name: list[i].getAttribute('data-positionname'),
company: list[i].getAttribute('data-company'),
salary: list[i].getAttribute('data-salary'),
require: list[i].querySelector('.li_b_l').childNodes[4].textContent.replace(/ |\n/g, ''),
})
}
return res
这里有一个调试技巧,获取数据的函数可以直接写在chrome的控制台中,方便调试
最后附上完整代码
const puppeteer = require('puppeteer');
(async () => {
// 启动浏览器
const browser = await puppeteer.launch({
headless: false, // 默认是无头模式,这里为了示范所以使用正常模式
})
// 控制浏览器打开新标签页面
const page = await browser.newPage()
// 在新标签中打开要爬取的网页
await page.goto('https://www.lagou.com/jobs/lis ... %2339;)
// 使用evaluate方法在浏览器中执行传入函数(完全的浏览器环境,所以函数内可以直接使用window、document等所有对象和方法)
let data = await page.evaluate(() => {
let list = document.querySelectorAll('.s_position_list .item_con_list li')
let res = []
for (let i = 0; i < list.length; i++) {
res.push({
name: list[i].getAttribute('data-positionname'),
company: list[i].getAttribute('data-company'),
salary: list[i].getAttribute('data-salary'),
require: list[i].querySelector('.li_b_l').childNodes[4].textContent.replace(/ |\n/g, ''),
})
}
return res
})
console.log(data)
})()
运行结果
动态网页的爬取到这里也已经完成了,但是puppeteer功能远不止这些,它还有很多强大的API可以使用。您可以转到官方文档。
第三期会讲到如何定时执行爬虫并存入数据库。 查看全部
java爬虫抓取动态网页(之前第一篇教程.js爬虫入门(一)爬取静态页面)
之前的第一篇爬虫教程,Node.js爬虫介绍(一)爬取静态页面讲解静态网页的爬取,很简单,但是如果遇到一些动态网页(ajax),可以直接用之前发送请求的方法我们都拿不到我们想要的数据,这时候需要爬取动态网页,selenium和puppeteer都不错。
这里推荐使用puppeteer,不为别的,只因为他是谷歌自己的,一直在维护更新。以下是翻译的官方文档介绍
Puppeteer 是一个 Node 库,提供一系列高级接口,通过 DevTools(开发者工具)协议控制 Chrome 或 Chromium(谷歌开源)。它默认以无头模式运行(无浏览器 UI),也可以通过配置以正常模式运行。
它可用于:
首先,我们必须在使用它之前安装它。默认安装会附带下载最新的 Chromium,大小约为 300M。
npm install puppeteer
如果本地已经有较新版本的chrome,可以只安装core版本,但是启动puppeteer时需要配置本地chrome的路径。
npm install puppeteer-core // 核心版本
假设我们现在要爬取拉狗网的前端招聘信息。这是一个动态页面。使用下面的示例尝试抓取。
因为chrome操作都是异步操作,为了避免回调地狱,推荐使用es7的async await。这种语法具有高度可读性,官方文档也是如此。
首先使用 puppeteer 启动浏览器并打开该动态页面
这里需要注意的是,如果使用的是本地浏览器,需要在启动浏览器配置中传入本地chrome路径
const browser = await puppeteer.launch({
executablePath: 'C:/Users/Administrator/AppData/Local/Google/Chrome/Application/chrome.exe'
})
在chrome环境中执行函数获取需要的数据然后返回节点的执行环境

上图是我们需要的数据的dom位置。在chrome环境执行的函数中,我们需要获取并整理需要的数据。
let list = document.querySelectorAll('.s_position_list .item_con_list li')
let res = []
for (let i = 0; i < list.length; i++) {
res.push({
name: list[i].getAttribute('data-positionname'),
company: list[i].getAttribute('data-company'),
salary: list[i].getAttribute('data-salary'),
require: list[i].querySelector('.li_b_l').childNodes[4].textContent.replace(/ |\n/g, ''),
})
}
return res
这里有一个调试技巧,获取数据的函数可以直接写在chrome的控制台中,方便调试
最后附上完整代码
const puppeteer = require('puppeteer');
(async () => {
// 启动浏览器
const browser = await puppeteer.launch({
headless: false, // 默认是无头模式,这里为了示范所以使用正常模式
})
// 控制浏览器打开新标签页面
const page = await browser.newPage()
// 在新标签中打开要爬取的网页
await page.goto('https://www.lagou.com/jobs/lis ... %2339;)
// 使用evaluate方法在浏览器中执行传入函数(完全的浏览器环境,所以函数内可以直接使用window、document等所有对象和方法)
let data = await page.evaluate(() => {
let list = document.querySelectorAll('.s_position_list .item_con_list li')
let res = []
for (let i = 0; i < list.length; i++) {
res.push({
name: list[i].getAttribute('data-positionname'),
company: list[i].getAttribute('data-company'),
salary: list[i].getAttribute('data-salary'),
require: list[i].querySelector('.li_b_l').childNodes[4].textContent.replace(/ |\n/g, ''),
})
}
return res
})
console.log(data)
})()
运行结果

动态网页的爬取到这里也已经完成了,但是puppeteer功能远不止这些,它还有很多强大的API可以使用。您可以转到官方文档。
第三期会讲到如何定时执行爬虫并存入数据库。
java爬虫抓取动态网页(什么是Webmagic.要使用Webmagic?期刊版面内容表表 )
网站优化 • 优采云 发表了文章 • 0 个评论 • 51 次浏览 • 2022-02-01 06:15
)
一、什么是 Webmagic。
要使用 Webmagic,首先需要了解 Webmagic 是什么。
webmagic 是一个开源的 Java 垂直爬虫框架。目标是简化爬虫的开发过程,让开发者专注于逻辑功能的开发。webmagic主要由Downloader(下载器)、PageProcesser(解析器)、Schedule(调度器)和Pipeline(管道)组成。
webmagic采用完全模块化设计,功能覆盖爬虫全生命周期(链接提取、页面下载、内容提取、持久化),支持多线程爬取、分布式爬取,并支持自动重试、自定义UA/等功能饼干。
webmagic 收录页面提取功能,开发者可以使用 css 选择器、xpath 和正则表达式提取链接和内容,并支持多个选择器链调用。
二、示例代码
(1)pom.xml 文件增加了新的依赖
us.codecraft`这里写代码片` webmagic-core
0.5.3
us.codecraft
webmagic-extension
0.5.3
(2)Scheduling定时任务设定,也可称为调度器。
import javax.annotation.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import org.springframework.transaction.annotation.Transactional;import com.zhibo.xmt.common.webmagic.xpager.popeline.XpaperZgtcbPopeline;import com.zhibo.xmt.common.webmagic.xpager.processor.XpaperZgtcbProcessor;import us.codecraft.webmagic.Spider;/**
* 爬取 xpaper http://i.xpaper.net/cnsports 版面信息数据
* 每周 二 、 四、日发布新期刊
* @author Bruce
*
*/@Component@EnableSchedulingpublic class XpaperWebmagicSchedulingConfig {
private final Logger logger = LoggerFactory.getLogger(XpaperWebmagicSchedulingConfig.class); public static final String BASE_URL = "http://i.xpaper.net/cnsports"; @Resource
private XpaperZgtcbPopeline xpaperZgtcbPopeline; /**
* 中国体彩报 xpaper全媒体数字报 版面内容抓取
*/
/**
* "0 0/1 18 * * ?" 每天18:00到18:59 没分钟执行一次
*
* "0 10 4 ? * *" 每天上午4:10触发
*/
@Transactional
@Scheduled(cron = "0 10 4 ? * *") public void createLotteryInfo(){
System.out.println("中国体彩报 xpaper全媒体数字报 版面内容抓取"); long startTime, endTime;
System.out.println("【爬虫开始】");
startTime = System.currentTimeMillis();
logger.info("爬取地址:" + BASE_URL); try {
Spider spider = Spider.create(new XpaperZgtcbProcessor());
spider.addUrl(BASE_URL);
spider.addPipeline(xpaperZgtcbPopeline);
spider.thread(5);
spider.setExitWhenComplete(true);
spider.start();
spider.stop();
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
endTime = System.currentTimeMillis();
System.out.println("【爬虫结束】");
System.out.println("中国体彩报 xpaper全媒体数字报 版面内容抓取耗时约" + ((endTime - startTime) / 1000) + "秒,已保存到数据库.");
}
}
(3)XpaperZgtcbProcessor解析器,解析要爬取的页面
<p>import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import com.zhibo.xmt.common.enums.common.EnumCommonStatus;import com.zhibo.xmt.common.util.DateUtil;import com.zhibo.xmt.common.vo.pagesub.Journal;import com.zhibo.xmt.common.vo.pagesub.JournalPage;import us.codecraft.webmagic.Page;import us.codecraft.webmagic.Site;import us.codecraft.webmagic.processor.PageProcessor;import us.codecraft.webmagic.selector.Selectable;/**
* 中国体彩报 xpaper全媒体数字报 版面内容抓取
* http://i.xpaper.net/cnsports
* @author Bruce
*
*/@Component
public class XpaperZgtcbProcessor implements PageProcessor{
private static Logger logger = LoggerFactory.getLogger(XpaperZgtcbProcessor.class);
// 正则表达式\\. \\转义java中的\ \.转义正则中的.
// 主域名
public static final String BASE_URL = "http://i.xpaper.net/cnsports";
private Site site = Site.me() .setDomain(BASE_URL) .setSleepTime(1000) .setRetryTimes(30) .setCharset("utf-8") .setTimeOut(30000) .setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31");
@Override
public Site getSite() {
return site;
}
@Override
public void process(Page page) {
if (page.getUrl().regex(BASE_URL).match()) {
String contentTitle = page.getHtml().xpath("//title/text()").toString();
/**
* System.out.println("issue:" + issue);
System.out.println("issueDesc:" + issueDesc);
System.out.println("contentTitle:" + contentTitle);
* contentTitle:中国体彩报 - 第1151期 - 第01版 - A1
issue: 1151
issueDesc:中国体彩报 - 第1151期
*/
String[] contentTitles = contentTitle.trim().split("-");
String issueStr = contentTitles[1].replaceAll("第", "").replaceAll("期", "").replaceAll(" ", "").trim().replaceAll("\\s*", "");
String issue = new String(issueStr);
//由于里面有空格,因此使用了多种方式去空格。
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(issue);
issue = m.replaceAll("");
issue = issue.replaceAll("\\u00A0","");
String issueDesc = contentTitles[0] + "-" + contentTitles[1];
Journal journal = new Journal();
journal.setTitle(issueDesc);
journal.setTitleDesc(contentTitle);
journal.setIssue(issue);
journal.setDate(DateUtil.getDateByFormat(DateUtil.getDateByFormat(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd"));
journal.setDateStr(DateUtil.getDateByFormat(new Date(), "yyyy-MM-dd"));
journal.setType(1);
journal.setStatus(EnumCommonStatus.NORMAL.getValue());
journal.setGrabDate(new Date());
journal.setCreatedAt(new Date());
journal.setUpdatedAt(new Date());
logger.info("期刊数据:" + journal.toString());
List list = page.getHtml().xpath("//div[@id='m1']/a").nodes();
if(list != null && list.size() > 0){
List journalPages = new ArrayList();
for(int i = 0; i < list.size(); i++){
Selectable s = list.get(i);
String link = s.links().toString();
String titleStr = s.xpath("//b/text()").toString();
if(StringUtils.isBlank(titleStr)){
titleStr = s.toString().split(">")[1].replaceAll(" 查看全部
java爬虫抓取动态网页(什么是Webmagic.要使用Webmagic?期刊版面内容表表
)
一、什么是 Webmagic。
要使用 Webmagic,首先需要了解 Webmagic 是什么。
webmagic 是一个开源的 Java 垂直爬虫框架。目标是简化爬虫的开发过程,让开发者专注于逻辑功能的开发。webmagic主要由Downloader(下载器)、PageProcesser(解析器)、Schedule(调度器)和Pipeline(管道)组成。
webmagic采用完全模块化设计,功能覆盖爬虫全生命周期(链接提取、页面下载、内容提取、持久化),支持多线程爬取、分布式爬取,并支持自动重试、自定义UA/等功能饼干。
webmagic 收录页面提取功能,开发者可以使用 css 选择器、xpath 和正则表达式提取链接和内容,并支持多个选择器链调用。
二、示例代码
(1)pom.xml 文件增加了新的依赖
us.codecraft`这里写代码片` webmagic-core
0.5.3
us.codecraft
webmagic-extension
0.5.3
(2)Scheduling定时任务设定,也可称为调度器。
import javax.annotation.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import org.springframework.transaction.annotation.Transactional;import com.zhibo.xmt.common.webmagic.xpager.popeline.XpaperZgtcbPopeline;import com.zhibo.xmt.common.webmagic.xpager.processor.XpaperZgtcbProcessor;import us.codecraft.webmagic.Spider;/**
* 爬取 xpaper http://i.xpaper.net/cnsports 版面信息数据
* 每周 二 、 四、日发布新期刊
* @author Bruce
*
*/@Component@EnableSchedulingpublic class XpaperWebmagicSchedulingConfig {
private final Logger logger = LoggerFactory.getLogger(XpaperWebmagicSchedulingConfig.class); public static final String BASE_URL = "http://i.xpaper.net/cnsports"; @Resource
private XpaperZgtcbPopeline xpaperZgtcbPopeline; /**
* 中国体彩报 xpaper全媒体数字报 版面内容抓取
*/
/**
* "0 0/1 18 * * ?" 每天18:00到18:59 没分钟执行一次
*
* "0 10 4 ? * *" 每天上午4:10触发
*/
@Transactional
@Scheduled(cron = "0 10 4 ? * *") public void createLotteryInfo(){
System.out.println("中国体彩报 xpaper全媒体数字报 版面内容抓取"); long startTime, endTime;
System.out.println("【爬虫开始】");
startTime = System.currentTimeMillis();
logger.info("爬取地址:" + BASE_URL); try {
Spider spider = Spider.create(new XpaperZgtcbProcessor());
spider.addUrl(BASE_URL);
spider.addPipeline(xpaperZgtcbPopeline);
spider.thread(5);
spider.setExitWhenComplete(true);
spider.start();
spider.stop();
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
endTime = System.currentTimeMillis();
System.out.println("【爬虫结束】");
System.out.println("中国体彩报 xpaper全媒体数字报 版面内容抓取耗时约" + ((endTime - startTime) / 1000) + "秒,已保存到数据库.");
}
}
(3)XpaperZgtcbProcessor解析器,解析要爬取的页面
<p>import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import com.zhibo.xmt.common.enums.common.EnumCommonStatus;import com.zhibo.xmt.common.util.DateUtil;import com.zhibo.xmt.common.vo.pagesub.Journal;import com.zhibo.xmt.common.vo.pagesub.JournalPage;import us.codecraft.webmagic.Page;import us.codecraft.webmagic.Site;import us.codecraft.webmagic.processor.PageProcessor;import us.codecraft.webmagic.selector.Selectable;/**
* 中国体彩报 xpaper全媒体数字报 版面内容抓取
* http://i.xpaper.net/cnsports
* @author Bruce
*
*/@Component
public class XpaperZgtcbProcessor implements PageProcessor{
private static Logger logger = LoggerFactory.getLogger(XpaperZgtcbProcessor.class);
// 正则表达式\\. \\转义java中的\ \.转义正则中的.
// 主域名
public static final String BASE_URL = "http://i.xpaper.net/cnsports";
private Site site = Site.me() .setDomain(BASE_URL) .setSleepTime(1000) .setRetryTimes(30) .setCharset("utf-8") .setTimeOut(30000) .setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31");
@Override
public Site getSite() {
return site;
}
@Override
public void process(Page page) {
if (page.getUrl().regex(BASE_URL).match()) {
String contentTitle = page.getHtml().xpath("//title/text()").toString();
/**
* System.out.println("issue:" + issue);
System.out.println("issueDesc:" + issueDesc);
System.out.println("contentTitle:" + contentTitle);
* contentTitle:中国体彩报 - 第1151期 - 第01版 - A1
issue: 1151
issueDesc:中国体彩报 - 第1151期
*/
String[] contentTitles = contentTitle.trim().split("-");
String issueStr = contentTitles[1].replaceAll("第", "").replaceAll("期", "").replaceAll(" ", "").trim().replaceAll("\\s*", "");
String issue = new String(issueStr);
//由于里面有空格,因此使用了多种方式去空格。
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(issue);
issue = m.replaceAll("");
issue = issue.replaceAll("\\u00A0","");
String issueDesc = contentTitles[0] + "-" + contentTitles[1];
Journal journal = new Journal();
journal.setTitle(issueDesc);
journal.setTitleDesc(contentTitle);
journal.setIssue(issue);
journal.setDate(DateUtil.getDateByFormat(DateUtil.getDateByFormat(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd"));
journal.setDateStr(DateUtil.getDateByFormat(new Date(), "yyyy-MM-dd"));
journal.setType(1);
journal.setStatus(EnumCommonStatus.NORMAL.getValue());
journal.setGrabDate(new Date());
journal.setCreatedAt(new Date());
journal.setUpdatedAt(new Date());
logger.info("期刊数据:" + journal.toString());
List list = page.getHtml().xpath("//div[@id='m1']/a").nodes();
if(list != null && list.size() > 0){
List journalPages = new ArrayList();
for(int i = 0; i < list.size(); i++){
Selectable s = list.get(i);
String link = s.links().toString();
String titleStr = s.xpath("//b/text()").toString();
if(StringUtils.isBlank(titleStr)){
titleStr = s.toString().split(">")[1].replaceAll("
java爬虫抓取动态网页(博客系列Java爬虫入门简介(一)——HttpClient请求 )
网站优化 • 优采云 发表了文章 • 0 个评论 • 35 次浏览 • 2022-01-30 02:07
)
博客系列
Java爬虫简介(一)——HttpClient请求(本文)
Java爬虫简介(二)——Jsoup解析HTML页面(本文)
在上一篇博客中,我们已经介绍了如何使用 HttpClient 来模拟客户端请求页面。在本篇博客中,我们将介绍如何解析获取的页面内容。
在上一节中,我们获得了页面的 HTML 源代码,但是这些源代码是提供给浏览器进行解析的。我们需要的数据其实就是页面上博客的标题、作者、简介、发布日期等。我们需要一种方法来从 HTML 源代码中解析这些信息,将其提取出来,并将其存储在文本或数据库中。在本篇博客中,我们将介绍使用 Jsoup 包来帮助我们解析页面和提取数据。
Jsoup是一个Java HTML解析器,可以直接解析一个URL地址或者解析HTML内容。它的主要功能包括解析 HTML 页面、通过 DOM 或 CSS 选择器查找和提取数据以及更改 HTML 内容。Jsoup的使用也很简单。使用Jsoup.parse(String str)方法解析我们之前获取的HTML内容得到一个Document类,剩下的工作就是从Document中选择我们需要的数据。例如,假设我们有一个收录以下内容的 HTML 页面:
第一篇博客
第二篇博客
第三篇博客
通过Jsoup,我们可以将以上三个博客的标题提取成一个List。使用方法如下:
首先,我们通过maven来介绍Jsoup
org.jsoup
jsoup
1.10.3
然后写Java来解析。
package org.hfutec.example;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
public class DataLearnerCrawler {
public static void main(String[] args) {
List titles = new ArrayList();
List urls = new ArrayList();
//假设我们获取的HTML的字符内容如下
String html = "<a href=\"url1\">第一篇博客</a><a href=\"url2\">第二篇博客</a><a href=\"url3\">第三篇博客</a>";
//第一步,将字符内容解析成一个Document类
Document doc = Jsoup.parse(html);
//第二步,根据我们需要得到的标签,选择提取相应标签的内容
Elements elements = doc.select("div[id=blog_list]").select("div[class=blog_title]");
for( Element element : elements ){
String title = element.text();
titles.add(title);
urls.add(element.select("a").attr("href"));
}
//输出测试
for( String title : titles ){
System.out.println(title);
}
for( String url : urls ){
System.out.println(url);
}
}
}
下面简单介绍一下Jsoup的解析过程。第一步是调用parse()方法把字符对象变成Document对象,然后我们对这个对象进行操作。一般来说,提取数据就是根据标签选择数据。select() 方法的语法格式与 javascript/css 选择器的语法格式相同。一般抽取一个标签,其属性值为指定的内容。得到的结果是一个Elements的集合,也就是Elements(因为可能有很多符合条件的标签,所以结果就是一个集合)。select() 方法可以一直持续到我们想要的标签集被选中(注意我们不必从标签层级中逐层选择,我们可以直接将 select() 方法写到我们需要的标签中,例如, 这里的示例代码可以直接写成 Elements elements = doc.select("div[class=blog_title]"); 效果是一样的)。对于选定的一组元素,我们可以通过循环提取每个所需的数据。例如,如果我们需要获取标签的文本信息,可以使用 text() 方法。如果我们需要获取对应的 HTML 属性信息,可以使用 attr() 方法。我们可以看到上述方法的输出如下:
更多Jsoup解析操作请参考以下内容:
1、
2、
一个实例
让我们继续上一个爬取数据的例子来学习官方的网站博客列表来解释一个例子。我们已经知道可以使用 Jsoup 来解析爬取的 HTML 页面内容。那么我们如何查看我们需要的内容对应的标签呢?以Chrome浏览器为例,我们需要爬取这个页面的博客。首先用Chrome浏览器打开网址,然后右击博客标题,点击“Inspect”,得到HTML页面。如下所示。
图2 右击标题
图3 点击元素父元素侧边的小三角关闭代码查看
图4 确认当前博客HTML代码的一致性
经过上面的操作,我们已经可以看到所有的博客标题等信息都存放在class=card div中了。所以,我们只需要注意这个标签中的内容是如何组织的,仅此而已。如下图所示,我们需要的信息所属的标签可以通过点击小三角展开得到。
因此,解析博客列表的代码可以写成如下。
package org.hfutec.example;
import org.apache.http.HttpEntity;
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 org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
public class DataLearnerCrawler {
public static void main(String[] args) {
String url = "http://www.datalearner.com/blog_list";
String rawHTML = null;
try {
rawHTML = getHTMLContent(url);
} catch (IOException e) {
e.printStackTrace();
}
//将当前页面转换成Jsoup的Document对象
Document doc = Jsoup.parse(rawHTML);
//获取所有的博客列表集合
Elements blogList = doc.select("div[class=card]");
//针对每个博客内容进行解析,并输出
for( Element element : blogList ){
String title = element.select("h4[class=card-title]").text();
String introduction = element.select("p[class=card-text]").text();
String author = element.select("span[class=fa fa-user]").text();
System.out.println("Title:\t"+title);
System.out.println("introduction:\t"+introduction);
System.out.println("Author:\t"+author);
System.out.println("--------------------------");
}
}
//根据url地址获取对应页面的HTML内容,我们将上一节中的内容打包成了一个方法,方便调用
private static String getHTMLContent( String url ) throws IOException {
//建立一个新的请求客户端
CloseableHttpClient httpClient = HttpClients.createDefault();
//使用HttpGet方式请求网址
HttpGet httpGet = new HttpGet(url);
//获取网址的返回结果
CloseableHttpResponse response = httpClient.execute(httpGet);
//获取返回结果中的实体
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
//关闭HttpEntity流
EntityUtils.consume(entity);
return content;
}
}
最终输出如下图所示:
查看全部
java爬虫抓取动态网页(博客系列Java爬虫入门简介(一)——HttpClient请求
)
博客系列
Java爬虫简介(一)——HttpClient请求(本文)
Java爬虫简介(二)——Jsoup解析HTML页面(本文)
在上一篇博客中,我们已经介绍了如何使用 HttpClient 来模拟客户端请求页面。在本篇博客中,我们将介绍如何解析获取的页面内容。
在上一节中,我们获得了页面的 HTML 源代码,但是这些源代码是提供给浏览器进行解析的。我们需要的数据其实就是页面上博客的标题、作者、简介、发布日期等。我们需要一种方法来从 HTML 源代码中解析这些信息,将其提取出来,并将其存储在文本或数据库中。在本篇博客中,我们将介绍使用 Jsoup 包来帮助我们解析页面和提取数据。
Jsoup是一个Java HTML解析器,可以直接解析一个URL地址或者解析HTML内容。它的主要功能包括解析 HTML 页面、通过 DOM 或 CSS 选择器查找和提取数据以及更改 HTML 内容。Jsoup的使用也很简单。使用Jsoup.parse(String str)方法解析我们之前获取的HTML内容得到一个Document类,剩下的工作就是从Document中选择我们需要的数据。例如,假设我们有一个收录以下内容的 HTML 页面:
第一篇博客
第二篇博客
第三篇博客
通过Jsoup,我们可以将以上三个博客的标题提取成一个List。使用方法如下:
首先,我们通过maven来介绍Jsoup
org.jsoup
jsoup
1.10.3
然后写Java来解析。
package org.hfutec.example;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
public class DataLearnerCrawler {
public static void main(String[] args) {
List titles = new ArrayList();
List urls = new ArrayList();
//假设我们获取的HTML的字符内容如下
String html = "<a href=\"url1\">第一篇博客</a><a href=\"url2\">第二篇博客</a><a href=\"url3\">第三篇博客</a>";
//第一步,将字符内容解析成一个Document类
Document doc = Jsoup.parse(html);
//第二步,根据我们需要得到的标签,选择提取相应标签的内容
Elements elements = doc.select("div[id=blog_list]").select("div[class=blog_title]");
for( Element element : elements ){
String title = element.text();
titles.add(title);
urls.add(element.select("a").attr("href"));
}
//输出测试
for( String title : titles ){
System.out.println(title);
}
for( String url : urls ){
System.out.println(url);
}
}
}
下面简单介绍一下Jsoup的解析过程。第一步是调用parse()方法把字符对象变成Document对象,然后我们对这个对象进行操作。一般来说,提取数据就是根据标签选择数据。select() 方法的语法格式与 javascript/css 选择器的语法格式相同。一般抽取一个标签,其属性值为指定的内容。得到的结果是一个Elements的集合,也就是Elements(因为可能有很多符合条件的标签,所以结果就是一个集合)。select() 方法可以一直持续到我们想要的标签集被选中(注意我们不必从标签层级中逐层选择,我们可以直接将 select() 方法写到我们需要的标签中,例如, 这里的示例代码可以直接写成 Elements elements = doc.select("div[class=blog_title]"); 效果是一样的)。对于选定的一组元素,我们可以通过循环提取每个所需的数据。例如,如果我们需要获取标签的文本信息,可以使用 text() 方法。如果我们需要获取对应的 HTML 属性信息,可以使用 attr() 方法。我们可以看到上述方法的输出如下:

更多Jsoup解析操作请参考以下内容:
1、
2、
一个实例
让我们继续上一个爬取数据的例子来学习官方的网站博客列表来解释一个例子。我们已经知道可以使用 Jsoup 来解析爬取的 HTML 页面内容。那么我们如何查看我们需要的内容对应的标签呢?以Chrome浏览器为例,我们需要爬取这个页面的博客。首先用Chrome浏览器打开网址,然后右击博客标题,点击“Inspect”,得到HTML页面。如下所示。

图2 右击标题

图3 点击元素父元素侧边的小三角关闭代码查看

图4 确认当前博客HTML代码的一致性
经过上面的操作,我们已经可以看到所有的博客标题等信息都存放在class=card div中了。所以,我们只需要注意这个标签中的内容是如何组织的,仅此而已。如下图所示,我们需要的信息所属的标签可以通过点击小三角展开得到。

因此,解析博客列表的代码可以写成如下。
package org.hfutec.example;
import org.apache.http.HttpEntity;
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 org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
public class DataLearnerCrawler {
public static void main(String[] args) {
String url = "http://www.datalearner.com/blog_list";
String rawHTML = null;
try {
rawHTML = getHTMLContent(url);
} catch (IOException e) {
e.printStackTrace();
}
//将当前页面转换成Jsoup的Document对象
Document doc = Jsoup.parse(rawHTML);
//获取所有的博客列表集合
Elements blogList = doc.select("div[class=card]");
//针对每个博客内容进行解析,并输出
for( Element element : blogList ){
String title = element.select("h4[class=card-title]").text();
String introduction = element.select("p[class=card-text]").text();
String author = element.select("span[class=fa fa-user]").text();
System.out.println("Title:\t"+title);
System.out.println("introduction:\t"+introduction);
System.out.println("Author:\t"+author);
System.out.println("--------------------------");
}
}
//根据url地址获取对应页面的HTML内容,我们将上一节中的内容打包成了一个方法,方便调用
private static String getHTMLContent( String url ) throws IOException {
//建立一个新的请求客户端
CloseableHttpClient httpClient = HttpClients.createDefault();
//使用HttpGet方式请求网址
HttpGet httpGet = new HttpGet(url);
//获取网址的返回结果
CloseableHttpResponse response = httpClient.execute(httpGet);
//获取返回结果中的实体
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
//关闭HttpEntity流
EntityUtils.consume(entity);
return content;
}
}
最终输出如下图所示:

java爬虫抓取动态网页(爬虫Python入门学习分三个阶段的几种方法和方法)
网站优化 • 优采云 发表了文章 • 0 个评论 • 50 次浏览 • 2022-01-23 21:21
学习爬虫 Python 入门容易吗?学习爬虫需要一定的基础,有编程基础的Python爬虫比较容易学习。但是你要多看多练,要有自己的逻辑思路。使用 Python 来实现自己的学习目的是值得的。如果是入门学习和理解,开始学习不难,但是很难深入学习,尤其是大型项目。
大多数爬虫遵循“发送请求-获取页面-解析页面-提取和存储内容”的过程,模拟使用浏览器获取网页信息的过程。向服务器发送请求后,我们会得到返回的页面。解析完页面后,我们就可以提取出我们想要的部分信息,存储到指定的文档或数据库中。爬虫Python入门学习分为三个阶段:
一、零基础阶段:
从零开始学爬虫,上手系统,从0开始爬虫。除了必要的理论知识,爬虫对于实际应用更重要。带你抓取4种主流网站数据,掌握主流爬虫爬取方法。
捕捉主流网站数据的能力是本阶段的学习目标
学习点:爬虫所需的计算机网络/前端/正则//xpath/CSS选择器基础知识;实现静态网页和动态网页两种主流网页类型的数据抓取;模拟登录、响应反爬、识别验证码等,难点详解;多线程、多进程等常见应用场景讲解
二、主流框架
主流框架Scrapy,实现海量数据抓取,提升从原生爬虫到框架的能力。学习后,可以彻底玩转Scrapy框架,开发属于自己的分布式爬虫系统,完全胜任Python中级工程师的工作。获得高效捕获大量数据的能力。
学习点:Scrapy框架知识讲解spider/FormRequest/CrawlSpider等;从单机爬虫到分布式爬虫系统;Scrapy突破了反爬虫的限制和Scrapy的原理;Scrapy 更高级的功能包括 sscrapy 信号、自定义中间件;一些海量数据结合Elasticsearch打造搜索引擎
三、爬虫
深度App数据抓取,爬虫能力提升,处理App数据抓取和数据可视化的能力不再局限于网络爬虫。从现在开始,拓展您的爬虫业务,提升您的核心竞争力。掌握App数据抓取,实现数据可视化
学习重点:学习主流抓包工具Fiddler/Mitmproxy的应用;4种App数据抓取实战,结合学习实践深入掌握App爬虫技巧;基于Docker构建多任务捕获系统,提高工作效率;掌握Pyecharts库基础,绘制基础图形、地图等进行数据可视化。
爬虫 Python 应用在很多领域,比如爬取数据、进行市场调研和商业分析;作为机器学习和数据挖掘的原创数据;爬取优质资源:图片、文字、视频。很容易掌握正确的方法,能够在短时间内爬取主流的网站数据。建议从爬虫 Python 入口开始就设置一个特定的目标。在目标的驱动下,学习会更有效率。 查看全部
java爬虫抓取动态网页(爬虫Python入门学习分三个阶段的几种方法和方法)
学习爬虫 Python 入门容易吗?学习爬虫需要一定的基础,有编程基础的Python爬虫比较容易学习。但是你要多看多练,要有自己的逻辑思路。使用 Python 来实现自己的学习目的是值得的。如果是入门学习和理解,开始学习不难,但是很难深入学习,尤其是大型项目。

大多数爬虫遵循“发送请求-获取页面-解析页面-提取和存储内容”的过程,模拟使用浏览器获取网页信息的过程。向服务器发送请求后,我们会得到返回的页面。解析完页面后,我们就可以提取出我们想要的部分信息,存储到指定的文档或数据库中。爬虫Python入门学习分为三个阶段:
一、零基础阶段:
从零开始学爬虫,上手系统,从0开始爬虫。除了必要的理论知识,爬虫对于实际应用更重要。带你抓取4种主流网站数据,掌握主流爬虫爬取方法。
捕捉主流网站数据的能力是本阶段的学习目标
学习点:爬虫所需的计算机网络/前端/正则//xpath/CSS选择器基础知识;实现静态网页和动态网页两种主流网页类型的数据抓取;模拟登录、响应反爬、识别验证码等,难点详解;多线程、多进程等常见应用场景讲解
二、主流框架
主流框架Scrapy,实现海量数据抓取,提升从原生爬虫到框架的能力。学习后,可以彻底玩转Scrapy框架,开发属于自己的分布式爬虫系统,完全胜任Python中级工程师的工作。获得高效捕获大量数据的能力。
学习点:Scrapy框架知识讲解spider/FormRequest/CrawlSpider等;从单机爬虫到分布式爬虫系统;Scrapy突破了反爬虫的限制和Scrapy的原理;Scrapy 更高级的功能包括 sscrapy 信号、自定义中间件;一些海量数据结合Elasticsearch打造搜索引擎
三、爬虫
深度App数据抓取,爬虫能力提升,处理App数据抓取和数据可视化的能力不再局限于网络爬虫。从现在开始,拓展您的爬虫业务,提升您的核心竞争力。掌握App数据抓取,实现数据可视化
学习重点:学习主流抓包工具Fiddler/Mitmproxy的应用;4种App数据抓取实战,结合学习实践深入掌握App爬虫技巧;基于Docker构建多任务捕获系统,提高工作效率;掌握Pyecharts库基础,绘制基础图形、地图等进行数据可视化。
爬虫 Python 应用在很多领域,比如爬取数据、进行市场调研和商业分析;作为机器学习和数据挖掘的原创数据;爬取优质资源:图片、文字、视频。很容易掌握正确的方法,能够在短时间内爬取主流的网站数据。建议从爬虫 Python 入口开始就设置一个特定的目标。在目标的驱动下,学习会更有效率。
java爬虫抓取动态网页(优雅的使用WebMagic框架,爬取、PhantomJS、Selenium、JavaScriptEngine)
网站优化 • 优采云 发表了文章 • 0 个评论 • 62 次浏览 • 2022-01-23 02:07
优雅使用WebMagic框架爬取唐诗笔苑诗人诗歌数据
同时在几种动态加载技术(HtmlUnit、PhantomJS、Selenium、JavaScriptEngine)中进行比较和选择
虽然 WebMagic 已经快两年没有维护了,但它是一个优秀的爬虫框架的实现。源码中有很多参考,尤其是爬虫多线程的控制。另外,由于爬取的页面是非结构化数据,所以数据保存到MongoDB中。技术准备pom.xml文件中的依赖很简单,没有用到Spring系列框架,所以有些地方已经编码实现了Spring提供的功能。项目结构项目说明
根据需要将数据保存到MongoDB数据库中,所以程序运行前必须设置resources/mongodb.properties文件
最好确保 MongoDB 的版本为 4.0 或更高。另外,MongoDB的用户管理比较麻烦。流程大致如下:首先需要创建一个用于存储数据的数据库,比如user_tangpoem,并存储任意数据(集合)使数据库生效,然后创建数据库
admin数据库的root用户,继续创建一个可以读写应用数据库user_tangpoem的用户,然后修改MongoDB配置文件以安全认证模式启动。重启数据库,选择admin数据库(使用admin)
使用db.auth()用刚刚创建的用户(非root用户)登录,返回1表示认证成功,选择user_tangpoem数据库(使用user_tangpoem),输入show 采集s,如果看到数据库时采集是最初创建的,表示用户创建成功。
详见MongoDB4.0.0远程连接和用户名密码认证登录配置——windows
爬虫以多线程方式运行。线程数和线程休眠时间可以在 resources/spider.properties 文件中设置。设置好数据库配置后,直接运行Main.main(),爬虫就会开始爬取。
线程休眠是WebMagic框架源码中每个线程爬取一个url后必须经过的一个过程,但是作者的文档并没有说明这个,请根据实际情况调整动态加载技术的选择1.PhantomJS和硒
WebMagic 的底层很好地使用了 HttpClient 来加载静态页面。对于动态页面,还有两种常用的 PhantomJSDownloader 和 SeleniumDownloader。
浏览器内核模拟浏览器行为的实现。其中,PhantomJS需要指定phantomjs.exe和要爬取的JS文件,seleniumDownloader需要指定chromedriver.exe,需要自己下载对应操作系统的版本。
使用起来并不难,在本项目中不会过多讨论。这里的关键是解释HtmlUnit
2. HtmlUnit
一款开源的Java页面分析工具,阅读完页面后,可以有效的使用HtmlUnit对页面内容进行分析。纯Java实现的模拟浏览器,无需指定外部文件。
虽然它对 JS 的支持还不完善,但总的来说 HtmlUnit 的内存消耗、CPU 消耗和效率都比 PhantomJS 和 Selenium 好,值得使用
本项目使用2.25版本的HtmlUnit,没有JS添加不成功的问题,但是使用2.3x版本会加载失败3. JavaScriptEngine
因为JavaScriptEngine有局限性,最明显的就是不支持jquery的语法,因为jquery使用的是浏览器的内置对象,而JS引擎本身并没有浏览器对象
当然,只要分析了页面的加载逻辑,如果不涉及浏览器对象的使用,或者转换了 JS 逻辑,仍然可以使用 JS 引擎,但是牺牲了通用性。本项目分析后使用JS引擎加载
4. 横向比较
经测试,三者对比如下
PhantomJS使用外部程序,所以JVM无法管理这部分硬件资源,需要打开任务管理器来爬取进程
经过分析,爬取步骤分为4个步骤:
抓取所有诗人的身份。一次调用接口即可获取所有诗人id,返回JSON格式的数据。接口地址为:抓取所有诗人信息。根据上一步的诗人id,逐一爬取对应诗人的详细信息。一共有2529条数据,然后调用接口2529次,返回JSON格式数据。接口地址为:{id} 抓取所有诗歌信息。根据上一步的诗人信息获取所有诗歌id,然后逐个调用接口获取诗歌的详细信息。总共大约有48000条数据,调用接口48000次返回html页面。需要模拟浏览器动态执行JS。接口地址为:{id}由于js是动态执行的,可能会超时,所以最后需要对还没有成功加载的诗歌信息进行处理,从数据库中读取这样的数据,形成url调用接口再次爬取直到所有数据都完成。这类数据约占1%,接口调用约480次。显然,如上所述,使用了广度优先遍历,所以当执行第三步时,数据将存储在数据库中。
优化后使用Java 8的nashorn JS引擎执行JS代码,不需要动态加载JS,所以不会出现4的问题
时间估计
根据爬取过程分析,忽略程序启动时间和调用接口获取诗人id的时间
在开启 8 个线程的并发模式下(使用 HtmlUnit 动态加载):
所需总数:2529 / 8 5 + 48000 (1 + 0.01)/ 8 * 10 ≈ 62596 秒 ≈ 1043 分钟 ≈ 17.4 小时
以上数据是本地测试得到的,配置为win10 8G i5-4210M 4核
优化后,使用JS引擎代替模拟浏览器动态加载JS,获取诗歌信息所需时间由10秒大幅缩短至6秒左右。因此,重新计算时间如下:
2529 / 8 5 + 48000 / 8 6 ≈ 37185 秒 ≈ 620 分钟 ≈ 10.3 小时
绩效评估
使用模拟浏览器动态加载JS时,观察JVM的使用情况,发现诗歌爬取阶段频繁出现Minor GC(新生代GC),大约每10秒一次,如下图所示。
后来发现多线程模拟浏览器加载页面行为非常占用内存(指同时打开8个浏览器加载网页),对象频繁创建和消费频繁。
建议在运行时通过-Xms -Xmx将JVM内存设置得更大,至少1G,然后将新生代的比例设置为更大的值,如-Xms2048M -Xmx2048M -XX:+UseParallelOldGC -XX:NewRatio =1
后来用JS引擎代替模拟浏览器动态加载JS,不仅速度明显提升,内存消耗也大大降低。Minor GC 平均每分钟发生一次,如下图所示。
最后附上GitHub项目地址: 查看全部
java爬虫抓取动态网页(优雅的使用WebMagic框架,爬取、PhantomJS、Selenium、JavaScriptEngine)
优雅使用WebMagic框架爬取唐诗笔苑诗人诗歌数据
同时在几种动态加载技术(HtmlUnit、PhantomJS、Selenium、JavaScriptEngine)中进行比较和选择
虽然 WebMagic 已经快两年没有维护了,但它是一个优秀的爬虫框架的实现。源码中有很多参考,尤其是爬虫多线程的控制。另外,由于爬取的页面是非结构化数据,所以数据保存到MongoDB中。技术准备pom.xml文件中的依赖很简单,没有用到Spring系列框架,所以有些地方已经编码实现了Spring提供的功能。项目结构项目说明
根据需要将数据保存到MongoDB数据库中,所以程序运行前必须设置resources/mongodb.properties文件
最好确保 MongoDB 的版本为 4.0 或更高。另外,MongoDB的用户管理比较麻烦。流程大致如下:首先需要创建一个用于存储数据的数据库,比如user_tangpoem,并存储任意数据(集合)使数据库生效,然后创建数据库
admin数据库的root用户,继续创建一个可以读写应用数据库user_tangpoem的用户,然后修改MongoDB配置文件以安全认证模式启动。重启数据库,选择admin数据库(使用admin)
使用db.auth()用刚刚创建的用户(非root用户)登录,返回1表示认证成功,选择user_tangpoem数据库(使用user_tangpoem),输入show 采集s,如果看到数据库时采集是最初创建的,表示用户创建成功。
详见MongoDB4.0.0远程连接和用户名密码认证登录配置——windows
爬虫以多线程方式运行。线程数和线程休眠时间可以在 resources/spider.properties 文件中设置。设置好数据库配置后,直接运行Main.main(),爬虫就会开始爬取。
线程休眠是WebMagic框架源码中每个线程爬取一个url后必须经过的一个过程,但是作者的文档并没有说明这个,请根据实际情况调整动态加载技术的选择1.PhantomJS和硒
WebMagic 的底层很好地使用了 HttpClient 来加载静态页面。对于动态页面,还有两种常用的 PhantomJSDownloader 和 SeleniumDownloader。
浏览器内核模拟浏览器行为的实现。其中,PhantomJS需要指定phantomjs.exe和要爬取的JS文件,seleniumDownloader需要指定chromedriver.exe,需要自己下载对应操作系统的版本。
使用起来并不难,在本项目中不会过多讨论。这里的关键是解释HtmlUnit
2. HtmlUnit
一款开源的Java页面分析工具,阅读完页面后,可以有效的使用HtmlUnit对页面内容进行分析。纯Java实现的模拟浏览器,无需指定外部文件。
虽然它对 JS 的支持还不完善,但总的来说 HtmlUnit 的内存消耗、CPU 消耗和效率都比 PhantomJS 和 Selenium 好,值得使用
本项目使用2.25版本的HtmlUnit,没有JS添加不成功的问题,但是使用2.3x版本会加载失败3. JavaScriptEngine
因为JavaScriptEngine有局限性,最明显的就是不支持jquery的语法,因为jquery使用的是浏览器的内置对象,而JS引擎本身并没有浏览器对象
当然,只要分析了页面的加载逻辑,如果不涉及浏览器对象的使用,或者转换了 JS 逻辑,仍然可以使用 JS 引擎,但是牺牲了通用性。本项目分析后使用JS引擎加载
4. 横向比较
经测试,三者对比如下
PhantomJS使用外部程序,所以JVM无法管理这部分硬件资源,需要打开任务管理器来爬取进程
经过分析,爬取步骤分为4个步骤:
抓取所有诗人的身份。一次调用接口即可获取所有诗人id,返回JSON格式的数据。接口地址为:抓取所有诗人信息。根据上一步的诗人id,逐一爬取对应诗人的详细信息。一共有2529条数据,然后调用接口2529次,返回JSON格式数据。接口地址为:{id} 抓取所有诗歌信息。根据上一步的诗人信息获取所有诗歌id,然后逐个调用接口获取诗歌的详细信息。总共大约有48000条数据,调用接口48000次返回html页面。需要模拟浏览器动态执行JS。接口地址为:{id}由于js是动态执行的,可能会超时,所以最后需要对还没有成功加载的诗歌信息进行处理,从数据库中读取这样的数据,形成url调用接口再次爬取直到所有数据都完成。这类数据约占1%,接口调用约480次。显然,如上所述,使用了广度优先遍历,所以当执行第三步时,数据将存储在数据库中。
优化后使用Java 8的nashorn JS引擎执行JS代码,不需要动态加载JS,所以不会出现4的问题
时间估计
根据爬取过程分析,忽略程序启动时间和调用接口获取诗人id的时间
在开启 8 个线程的并发模式下(使用 HtmlUnit 动态加载):
所需总数:2529 / 8 5 + 48000 (1 + 0.01)/ 8 * 10 ≈ 62596 秒 ≈ 1043 分钟 ≈ 17.4 小时
以上数据是本地测试得到的,配置为win10 8G i5-4210M 4核
优化后,使用JS引擎代替模拟浏览器动态加载JS,获取诗歌信息所需时间由10秒大幅缩短至6秒左右。因此,重新计算时间如下:
2529 / 8 5 + 48000 / 8 6 ≈ 37185 秒 ≈ 620 分钟 ≈ 10.3 小时
绩效评估
使用模拟浏览器动态加载JS时,观察JVM的使用情况,发现诗歌爬取阶段频繁出现Minor GC(新生代GC),大约每10秒一次,如下图所示。
后来发现多线程模拟浏览器加载页面行为非常占用内存(指同时打开8个浏览器加载网页),对象频繁创建和消费频繁。
建议在运行时通过-Xms -Xmx将JVM内存设置得更大,至少1G,然后将新生代的比例设置为更大的值,如-Xms2048M -Xmx2048M -XX:+UseParallelOldGC -XX:NewRatio =1
后来用JS引擎代替模拟浏览器动态加载JS,不仅速度明显提升,内存消耗也大大降低。Minor GC 平均每分钟发生一次,如下图所示。
最后附上GitHub项目地址:
java爬虫抓取动态网页(java爬虫的大概流程是怎么样的呢?-八维教育)
网站优化 • 优采云 发表了文章 • 0 个评论 • 42 次浏览 • 2022-01-19 12:05
java爬虫抓取动态网页,爬虫可以抓取通过网页抓取的全部内容,但是大多数情况下,爬虫只能抓取部分网页,因为我们的网站首页往往都很小,每个页面都有好几百k,但是部分页面是空白页面,就抓取不到全部内容。所以我们只要获取到了页面上所有的标题、属性、在什么位置,那么我们就能够抓取到整个页面。那么爬虫的大概流程是怎么样的呢?首先要获取到网页首页的伪装数据,伪装数据大概就是网页所有的内容和文本信息以及它们对应的id,这个id不是每个页面都能够获取到的,获取到id后要通过url提取伪装数据,这个url可以在以后的爬虫文章中专门描述。
获取完伪装数据,就可以开始爬取全部网页,爬虫可以抓取的全部网页,还是那句话,网页所有的信息大多数都在首页,但是没有什么特殊的地方,只要首页没有人操作,那么爬虫一般都可以抓取全部内容。当然还可以根据抓取的内容爬取到网页其他页面的页面,爬虫只抓取首页不放过全部内容,在这里,只爬取首页就可以了。爬虫一般爬取的网页,可以统一把它理解为java爬虫一般实现一个爬虫流程就是以下步骤了。
1、获取页面伪装数据。
2、提取页面内容。
3、获取外链。
4、组合parsemap,获取全部内容。
5、保存。
6、定时发送邮件或其他重要指令。pagecut我们先来看看页面伪装数据,让我们把页面伪装数据想象成是一个代码块,代码块的意思就是指某段代码能够获取某段代码内容的地方,页面伪装数据的不同代码块就相当于不同的段代码。比如:代码块1:basic_tag_css代码块2:loadingimg_getter代码块3:roots(存放/border-top-template/basic_tag_css)代码块4:title代码块5:comment_data代码块6:tag_img首先来看看我们可以通过什么样的代码块来获取首页的伪装数据。
如果我们只想抓取页面伪装数据的话,首先要拿到页面伪装数据所在的代码块,把basic_tag_css存入到bytecode的变量中。再把loadingimg_getter存入到bytecode的变量中。再把roots(存放/border-top-template/loading/get_border_top_image)存入到bytecode的变量中。
再把title存入到bytecode的变量中。还有一个办法是通过反编译代码块进行再次提取该页面中的伪装数据,但是由于我们获取首页可能没有代码块所在的内容就没有用处了,所以我们决定放弃这种方法。pagecut再看看我们提取出来的页面内容,要想获取到伪装数据所在的页面的内容,我们要知道页面里所有的文本信息以及它们对应的id。比。 查看全部
java爬虫抓取动态网页(java爬虫的大概流程是怎么样的呢?-八维教育)
java爬虫抓取动态网页,爬虫可以抓取通过网页抓取的全部内容,但是大多数情况下,爬虫只能抓取部分网页,因为我们的网站首页往往都很小,每个页面都有好几百k,但是部分页面是空白页面,就抓取不到全部内容。所以我们只要获取到了页面上所有的标题、属性、在什么位置,那么我们就能够抓取到整个页面。那么爬虫的大概流程是怎么样的呢?首先要获取到网页首页的伪装数据,伪装数据大概就是网页所有的内容和文本信息以及它们对应的id,这个id不是每个页面都能够获取到的,获取到id后要通过url提取伪装数据,这个url可以在以后的爬虫文章中专门描述。
获取完伪装数据,就可以开始爬取全部网页,爬虫可以抓取的全部网页,还是那句话,网页所有的信息大多数都在首页,但是没有什么特殊的地方,只要首页没有人操作,那么爬虫一般都可以抓取全部内容。当然还可以根据抓取的内容爬取到网页其他页面的页面,爬虫只抓取首页不放过全部内容,在这里,只爬取首页就可以了。爬虫一般爬取的网页,可以统一把它理解为java爬虫一般实现一个爬虫流程就是以下步骤了。
1、获取页面伪装数据。
2、提取页面内容。
3、获取外链。
4、组合parsemap,获取全部内容。
5、保存。
6、定时发送邮件或其他重要指令。pagecut我们先来看看页面伪装数据,让我们把页面伪装数据想象成是一个代码块,代码块的意思就是指某段代码能够获取某段代码内容的地方,页面伪装数据的不同代码块就相当于不同的段代码。比如:代码块1:basic_tag_css代码块2:loadingimg_getter代码块3:roots(存放/border-top-template/basic_tag_css)代码块4:title代码块5:comment_data代码块6:tag_img首先来看看我们可以通过什么样的代码块来获取首页的伪装数据。
如果我们只想抓取页面伪装数据的话,首先要拿到页面伪装数据所在的代码块,把basic_tag_css存入到bytecode的变量中。再把loadingimg_getter存入到bytecode的变量中。再把roots(存放/border-top-template/loading/get_border_top_image)存入到bytecode的变量中。
再把title存入到bytecode的变量中。还有一个办法是通过反编译代码块进行再次提取该页面中的伪装数据,但是由于我们获取首页可能没有代码块所在的内容就没有用处了,所以我们决定放弃这种方法。pagecut再看看我们提取出来的页面内容,要想获取到伪装数据所在的页面的内容,我们要知道页面里所有的文本信息以及它们对应的id。比。
java爬虫抓取动态网页(如何java写/实现网络爬虫抓取网页原理即是保存)
网站优化 • 优采云 发表了文章 • 0 个评论 • 64 次浏览 • 2022-01-18 18:10
如何编写/实现网络爬虫以在java中爬取网页
原理是保存cookie数据,登录后保存cookie。以后每次爬取页面,都会在header信息中发送cookie。系统根据 cookie 判断用户。有了cookie,就有了登录状态,后续的访问都是基于这个cookie对应的用户。补充:Java是一种可以编写跨平台应用软件的聪明才智。
如图:抓取选中地点的a标签下的链接,然后在控制台循环打印出url。如何通过Java代码实现对网页数据的指定爬取,我总结了Jsoup.Jar会在以下步骤中用到宝:人老了,才能有安宁芬芳的状态。就像窗前长出的一株花草,窗外的微风和光线,都是云的赐予,自然而有趣。似乎不是一朵花,而是一片云雾缭绕的热闹气氛。
将Jsoup.jar包导入到项目中,开始认真写诗,仔细检查每一个字,因为有你的影子
获取 URL 指定的 URL 或文档指定的正文。我希望我能幸运地留在你身边,而不是被别人取代。
获取网页中超链接的标题和链接
真实分享网络爬虫java实现原理(源码更好),放心;不管真假,我们都要对自己负责。
最近需要实现一个java网络爬虫来动态爬取其他网站热点新闻。分担复杂度的方法是使用java相关的类来模拟浏览器下载网页,然后使用DOM等技术下载网页,从网页中获取你需要的内容。但是,强烈建议您使用 HttpClient 和 HttpParse 框架来轻松实现网络爬取功能。HttpClient框架主要实现从WEB服务器下载网页数据。不幸的是,所有的旅伴都是临时的。终于一个人长大,跟着不同的团队,最后一个人一个人长大。
如何实现一个Java网络爬虫?你不知道我为你辗转反侧哭泣枕头的那些夜晚你从来不在意
网络爬虫是一种自动提取网页的程序。它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成部分。传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL,在抓取网页的过程中不断地从当前页面中提取新的URL并放入队列中。
如何用java代码实现网络爬虫解析
如何在 Java 中实现网络爬虫
有没有人有java网络爬虫抓取图片的源码
大多数网络快照是在网页上带有图像 url 的快照。高级网络抓包支持部分Javascript,其实原理和javascript中抓取html页面,解析拼接图片地址是一样的。
分享java的爬虫代码,最好爬CNKI万方的参考书目。如果有项目,可以帮忙上传。. .
下面介绍知乎爬虫源码及涉及的主要技术点:(1)程序包组织(2)模拟登录(爬虫主要技术点1)@ > 爬取到需要登录的网站数据,模拟登录是必要的一步,而且往往难度很大。知乎爬虫的模拟登录可以是一个很好的案例。 查看全部
java爬虫抓取动态网页(如何java写/实现网络爬虫抓取网页原理即是保存)
如何编写/实现网络爬虫以在java中爬取网页
原理是保存cookie数据,登录后保存cookie。以后每次爬取页面,都会在header信息中发送cookie。系统根据 cookie 判断用户。有了cookie,就有了登录状态,后续的访问都是基于这个cookie对应的用户。补充:Java是一种可以编写跨平台应用软件的聪明才智。
如图:抓取选中地点的a标签下的链接,然后在控制台循环打印出url。如何通过Java代码实现对网页数据的指定爬取,我总结了Jsoup.Jar会在以下步骤中用到宝:人老了,才能有安宁芬芳的状态。就像窗前长出的一株花草,窗外的微风和光线,都是云的赐予,自然而有趣。似乎不是一朵花,而是一片云雾缭绕的热闹气氛。
将Jsoup.jar包导入到项目中,开始认真写诗,仔细检查每一个字,因为有你的影子
获取 URL 指定的 URL 或文档指定的正文。我希望我能幸运地留在你身边,而不是被别人取代。
获取网页中超链接的标题和链接
真实分享网络爬虫java实现原理(源码更好),放心;不管真假,我们都要对自己负责。
最近需要实现一个java网络爬虫来动态爬取其他网站热点新闻。分担复杂度的方法是使用java相关的类来模拟浏览器下载网页,然后使用DOM等技术下载网页,从网页中获取你需要的内容。但是,强烈建议您使用 HttpClient 和 HttpParse 框架来轻松实现网络爬取功能。HttpClient框架主要实现从WEB服务器下载网页数据。不幸的是,所有的旅伴都是临时的。终于一个人长大,跟着不同的团队,最后一个人一个人长大。
如何实现一个Java网络爬虫?你不知道我为你辗转反侧哭泣枕头的那些夜晚你从来不在意
网络爬虫是一种自动提取网页的程序。它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成部分。传统爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL,在抓取网页的过程中不断地从当前页面中提取新的URL并放入队列中。
如何用java代码实现网络爬虫解析
如何在 Java 中实现网络爬虫
有没有人有java网络爬虫抓取图片的源码
大多数网络快照是在网页上带有图像 url 的快照。高级网络抓包支持部分Javascript,其实原理和javascript中抓取html页面,解析拼接图片地址是一样的。
分享java的爬虫代码,最好爬CNKI万方的参考书目。如果有项目,可以帮忙上传。. .
下面介绍知乎爬虫源码及涉及的主要技术点:(1)程序包组织(2)模拟登录(爬虫主要技术点1)@ > 爬取到需要登录的网站数据,模拟登录是必要的一步,而且往往难度很大。知乎爬虫的模拟登录可以是一个很好的案例。
java爬虫抓取动态网页(使用java语言开发的一款开源的爬虫工具(Heritrix))
网站优化 • 优采云 发表了文章 • 0 个评论 • 163 次浏览 • 2022-01-16 17:16
今天要和大家分享的是一款使用java语言开发的开源爬虫工具----Heritrix。
大家好,我是奋斗中的小强001。今天的内容将推荐一个用java开发的开源爬虫工具(Heritrix),希望对大家有所帮助。
介绍
Heritrix是java开发的开源网络爬虫,用户可以使用它从互联网上爬取想要的资源。它最好的地方在于其良好的扩展性,方便用户实现自己的爬取逻辑。它是 SourceForge 上的开源产品。
它是如何工作的和工作流程
Heritrix的爬取工作主要由两个核心模块完成,一个是core class核心类,另一个是pluggable modules插件模块。
它的核心类是整个爬虫开发包的核心,可以在此基础上进行定制,但核心类不能被覆盖。反之,可以直接更换插件模块,插件模块相当于插件类型。组件,您也可以使用自己实现的逻辑来替换插件模块。这样就可以更好的根据自己的业务需求自定义爬虫的爬取需求。
整个heritrix技术的工作原理和工作流程是由CrawlController下载控制器决定的,它是整个爬虫操作的启动器,控制着一个爬虫爬取的开始和结束,然后边界控制器Frontier负责采集采集url,下载控制器负责从边界控制器获取对应的url,交给对应的线程池处理。组织和处理。
因为heritrix的url爬取工作是由多个线程执行的,每个线程对应一个url,对应的处理器链执行一次。因此,在整个爬取过程中,最重要的是处理器链。让我们看看处理器链如何处理 url 处理。
第一个是预取链。顾名思义,预取链就是在处理url之前提前准备一些先决条件。
提取链就是将url对应的网页上的所有信息下载整理,然后写入对应的请求响应内容。
提取链:在完成上一步的内容提取后,提取链主要负责提取页面上的a标签,然后提取其他对应的url。
写链主要是把所有的结果组织起来,然后存储起来。
提交链:就是对url做最后的整理工作,然后在采集到的页面上提交其他url,只要把任务范围内的url提交给Frontier,让它做其他的爬取工作。
四、heritrix3安装下载教程1)下载说明
下载heritrix3.x版本的方法还有很多。下面我们推荐几种常用的下载方式:
1、首先推荐heritrix官网直接下载最新版本,因为官网提供的版本是最权威的最新版本,没有bug。它们已经过官方测试,所以它是我们的第一个下载渠道。,但官网地址在国外,有时需要翻墙访问。
2、其次,我们可以直接在GitHub上下载,因为GitHub是源代码下载的权威网站,下载后可以直接使用开发工具直接编译,但是GitHub优先推荐发布版本的儿子。GitHub仓库地址:
2)环境说明
Heritrix对环境依赖有版本要求,所以需要在环境配置的上下文中进行说明。本文文章及以下应用均基于heritrix3.2的版本,该版本所依赖的Java环境JDK为1.7。目前,3.2 版本似乎不支持 jdk1.8。如果将来支持它,我们也会这样做。详细说明和备注。
五、在Linux系统上配置环境变量
按照上面截图的步骤,首先需要配置JDK的环境变量。一般来说,学习爬虫的同学应该对Java非常熟悉。Java_home的环境变量可以直接按照上图的步骤进行配置。故意重复。
第三,heritrix启动和执行都需要权限才能正常启动,所以需要按照上图中的命令配置执行权限。
第三,heritrix启动和执行都需要权限才能正常启动,所以需要按照上图中的命令配置执行权限。
六、启动并运行
由于我们的下载、安装和环境变量配置操作都是在Linux系统上完成的,所以我们在启动heritrix的时候,也需要从命令行启动它。下图显示了我们的启动命令方法和控制台的详细信息。,heritrix登录的默认登录名和密码为admin。
以上步骤完成后,说明heritrix已经正常启动,我们可以在浏览器中访问heritrix的web界面了。默认访问地址为:localhost:8443,即web界面的访问地址。需要注意的是,浏览器的请求方式必须是HTTPS访问。
今天的内容就分享到这里,欢迎大家点赞关注!谢谢! 查看全部
java爬虫抓取动态网页(使用java语言开发的一款开源的爬虫工具(Heritrix))
今天要和大家分享的是一款使用java语言开发的开源爬虫工具----Heritrix。
大家好,我是奋斗中的小强001。今天的内容将推荐一个用java开发的开源爬虫工具(Heritrix),希望对大家有所帮助。
介绍
Heritrix是java开发的开源网络爬虫,用户可以使用它从互联网上爬取想要的资源。它最好的地方在于其良好的扩展性,方便用户实现自己的爬取逻辑。它是 SourceForge 上的开源产品。
它是如何工作的和工作流程
Heritrix的爬取工作主要由两个核心模块完成,一个是core class核心类,另一个是pluggable modules插件模块。
它的核心类是整个爬虫开发包的核心,可以在此基础上进行定制,但核心类不能被覆盖。反之,可以直接更换插件模块,插件模块相当于插件类型。组件,您也可以使用自己实现的逻辑来替换插件模块。这样就可以更好的根据自己的业务需求自定义爬虫的爬取需求。
整个heritrix技术的工作原理和工作流程是由CrawlController下载控制器决定的,它是整个爬虫操作的启动器,控制着一个爬虫爬取的开始和结束,然后边界控制器Frontier负责采集采集url,下载控制器负责从边界控制器获取对应的url,交给对应的线程池处理。组织和处理。
因为heritrix的url爬取工作是由多个线程执行的,每个线程对应一个url,对应的处理器链执行一次。因此,在整个爬取过程中,最重要的是处理器链。让我们看看处理器链如何处理 url 处理。
第一个是预取链。顾名思义,预取链就是在处理url之前提前准备一些先决条件。
提取链就是将url对应的网页上的所有信息下载整理,然后写入对应的请求响应内容。
提取链:在完成上一步的内容提取后,提取链主要负责提取页面上的a标签,然后提取其他对应的url。
写链主要是把所有的结果组织起来,然后存储起来。
提交链:就是对url做最后的整理工作,然后在采集到的页面上提交其他url,只要把任务范围内的url提交给Frontier,让它做其他的爬取工作。
四、heritrix3安装下载教程1)下载说明
下载heritrix3.x版本的方法还有很多。下面我们推荐几种常用的下载方式:
1、首先推荐heritrix官网直接下载最新版本,因为官网提供的版本是最权威的最新版本,没有bug。它们已经过官方测试,所以它是我们的第一个下载渠道。,但官网地址在国外,有时需要翻墙访问。
2、其次,我们可以直接在GitHub上下载,因为GitHub是源代码下载的权威网站,下载后可以直接使用开发工具直接编译,但是GitHub优先推荐发布版本的儿子。GitHub仓库地址:
2)环境说明
Heritrix对环境依赖有版本要求,所以需要在环境配置的上下文中进行说明。本文文章及以下应用均基于heritrix3.2的版本,该版本所依赖的Java环境JDK为1.7。目前,3.2 版本似乎不支持 jdk1.8。如果将来支持它,我们也会这样做。详细说明和备注。
五、在Linux系统上配置环境变量
按照上面截图的步骤,首先需要配置JDK的环境变量。一般来说,学习爬虫的同学应该对Java非常熟悉。Java_home的环境变量可以直接按照上图的步骤进行配置。故意重复。
第三,heritrix启动和执行都需要权限才能正常启动,所以需要按照上图中的命令配置执行权限。
第三,heritrix启动和执行都需要权限才能正常启动,所以需要按照上图中的命令配置执行权限。
六、启动并运行
由于我们的下载、安装和环境变量配置操作都是在Linux系统上完成的,所以我们在启动heritrix的时候,也需要从命令行启动它。下图显示了我们的启动命令方法和控制台的详细信息。,heritrix登录的默认登录名和密码为admin。
以上步骤完成后,说明heritrix已经正常启动,我们可以在浏览器中访问heritrix的web界面了。默认访问地址为:localhost:8443,即web界面的访问地址。需要注意的是,浏览器的请求方式必须是HTTPS访问。
今天的内容就分享到这里,欢迎大家点赞关注!谢谢!
java爬虫抓取动态网页( WebMagic使用slf4j-log4j12测试方法 )
网站优化 • 优采云 发表了文章 • 0 个评论 • 65 次浏览 • 2022-01-16 08:14
WebMagic使用slf4j-log4j12测试方法
)
<p>WebMagic的架构设计参照了Scrapy,而实现则应用了HttpClient、Jsoup等Java成熟的工具。<br /> <br /> WebMagic由四个组件(Downloader、PageProcessor、Scheduler、Pipeline)构成:
Downloader : 下载器PageProcessor: 页面解析器Scheduler: 任务分配、url去重Pipeline:数据存储、处理
WebMagic数据流转的对象:
Request : 一个Request对应一个URL地址 。它是是PageProcessor控制Downloader唯一方式。Page : 代表了从Downloader下载到的内容ResultItems : 相当于一个Map,它保存PageProcessor处理的结果,供Pipeline使用。
爬虫引擎–Spider:
Spider是WebMagic内部流程的核心,上面的四个组件都相当于Spider的一个属性,通过设置这个属性可以实现不同的功能。Spider也是WebMagic操作的入口,它封装了爬虫的创建、启动、停止、多线程等功能
<a id="_MavenWebMagic_26"></a>使用 Maven来安装WebMagic
us.codecraft
webmagic-core
0.7.3
us.codecraft
webmagic-extension
0.7.3
</p>
WebMagic 使用 slf4j-log4j12 作为 slf4j 的实现。如果自己自定义slf4j的实现,需要从项目中去掉这个依赖。
us.codecraft
webmagic-extension
0.7.3
org.slf4j
slf4j-log4j12
如果你不使用Maven,可以去下载最新的jar包,下载后解压,然后导入到项目中。
开始开发第一个爬虫
在项目中添加WebMagic的依赖后,就可以开始第一个爬虫的开发了!
下面是一个测试,点击main方法,选择“运行”看看是否正常运行。
package com.example.demo;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
public class DemoPageGet implements PageProcessor {
private Site site = Site.me();
@Override
public void process(Page page) {
System.out.println(page.getHtml());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new DemoPageGet()).addUrl("http://httpbin.org/get").run();
}
}
编写一个基本的爬虫
在WebMagic中,实现一个基本的爬虫只需要写一个实现PageProcessor接口的类。
这一部分我们通过GithubRepoPageProcessor的例子直接介绍PageProcessor的编写方式。
PageProcessor的定制分为爬虫配置、页面元素提取和链接发现三个部分。
public class GithubRepoPageProcessor implements PageProcessor {
// 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
@Override
// process是定制爬虫逻辑的核心接口,在这里编写抽取逻辑
public void process(Page page) {
// 部分二:定义如何抽取页面信息,并保存下来
page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());
page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString());
if (page.getResultItems().get("name") == null) {
//skip this page
page.setSkip(true);
}
page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));
// 部分三:从页面发现后续的url地址来抓取
page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/[\\w\\-]+/[\\w\\-]+)").all());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从"https://github.com/code4craft"开始抓
.addUrl("https://github.com/code4craft")
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
}
附加请求的链接
首先,通过正则表达式匹配或拼接出链接,例如:page.getHtml().links().regex("").all()
通过 addTargetRequests 方法 page.addTargetRequests(url) 将这些链接添加到要爬取的队列中。
爬虫的配置
Spider:爬虫程序的入口,可以通过set方法设置Spider的其他组件(Downloader、Scheduler、Pipeline)。
Site:站点本身的一些配置信息,如编码、HTTP头、超时、重试策略等,代理等,可以通过设置Site对象来配置。
配置 http 代理。从版本0.7.1开始,WebMagic开始使用新的代理APIProxyProvider,因为ProxyProvider定位更像是一个“组件”而不是Site的“配置”,所以代理不再从站点设置,但由 HttpClientDownloader 设置。
查看官方文档了解更多详情。
页面元素的提取
WebMagic 中使用了三种主要的数据提取技术:
使用管道保存结果
WebMagic 用来保存结果的组件称为管道。
比如我们通过“控制台输出”做的事情,也是通过一个内置的Pipeline来完成的,这个Pipeline叫做ConsolePipeline。
那么,我现在想把结果保存成Json格式,怎么做呢?
我只需要将 Pipeline 的实现替换为“JsonFilePipeline”即可。
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从"https://github.com/code4craft"开始抓
.addUrl("https://github.com/code4craft")
.addPipeline(new JsonFilePipeline("./webmagic"))
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
模拟 POST 请求方法
0.7.1版以后放弃了nameValuePair的老写法,通过在Request对象中添加Method和requestBody来实现。
Request request = new Request("http://xxx/path");
request.setMethod(HttpConstant.Method.POST);
request.setRequestBody(HttpRequestBody.json("{'id':1}","utf-8"));
HttpRequestBody内置多种初始化方法,支持最常见的表单提交、json提交等方法。
查看全部
java爬虫抓取动态网页(
WebMagic使用slf4j-log4j12测试方法
)
<p>WebMagic的架构设计参照了Scrapy,而实现则应用了HttpClient、Jsoup等Java成熟的工具。<br />

Downloader : 下载器PageProcessor: 页面解析器Scheduler: 任务分配、url去重Pipeline:数据存储、处理
WebMagic数据流转的对象:
Request : 一个Request对应一个URL地址 。它是是PageProcessor控制Downloader唯一方式。Page : 代表了从Downloader下载到的内容ResultItems : 相当于一个Map,它保存PageProcessor处理的结果,供Pipeline使用。
爬虫引擎–Spider:
Spider是WebMagic内部流程的核心,上面的四个组件都相当于Spider的一个属性,通过设置这个属性可以实现不同的功能。Spider也是WebMagic操作的入口,它封装了爬虫的创建、启动、停止、多线程等功能
<a id="_MavenWebMagic_26"></a>使用 Maven来安装WebMagic
us.codecraft
webmagic-core
0.7.3
us.codecraft
webmagic-extension
0.7.3
</p>

WebMagic 使用 slf4j-log4j12 作为 slf4j 的实现。如果自己自定义slf4j的实现,需要从项目中去掉这个依赖。
us.codecraft
webmagic-extension
0.7.3
org.slf4j
slf4j-log4j12
如果你不使用Maven,可以去下载最新的jar包,下载后解压,然后导入到项目中。
开始开发第一个爬虫
在项目中添加WebMagic的依赖后,就可以开始第一个爬虫的开发了!
下面是一个测试,点击main方法,选择“运行”看看是否正常运行。
package com.example.demo;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
public class DemoPageGet implements PageProcessor {
private Site site = Site.me();
@Override
public void process(Page page) {
System.out.println(page.getHtml());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new DemoPageGet()).addUrl("http://httpbin.org/get").run();
}
}
编写一个基本的爬虫
在WebMagic中,实现一个基本的爬虫只需要写一个实现PageProcessor接口的类。
这一部分我们通过GithubRepoPageProcessor的例子直接介绍PageProcessor的编写方式。
PageProcessor的定制分为爬虫配置、页面元素提取和链接发现三个部分。
public class GithubRepoPageProcessor implements PageProcessor {
// 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
@Override
// process是定制爬虫逻辑的核心接口,在这里编写抽取逻辑
public void process(Page page) {
// 部分二:定义如何抽取页面信息,并保存下来
page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());
page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString());
if (page.getResultItems().get("name") == null) {
//skip this page
page.setSkip(true);
}
page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));
// 部分三:从页面发现后续的url地址来抓取
page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/[\\w\\-]+/[\\w\\-]+)").all());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从"https://github.com/code4craft"开始抓
.addUrl("https://github.com/code4craft")
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
}
附加请求的链接
首先,通过正则表达式匹配或拼接出链接,例如:page.getHtml().links().regex("").all()
通过 addTargetRequests 方法 page.addTargetRequests(url) 将这些链接添加到要爬取的队列中。
爬虫的配置
Spider:爬虫程序的入口,可以通过set方法设置Spider的其他组件(Downloader、Scheduler、Pipeline)。

Site:站点本身的一些配置信息,如编码、HTTP头、超时、重试策略等,代理等,可以通过设置Site对象来配置。

配置 http 代理。从版本0.7.1开始,WebMagic开始使用新的代理APIProxyProvider,因为ProxyProvider定位更像是一个“组件”而不是Site的“配置”,所以代理不再从站点设置,但由 HttpClientDownloader 设置。
查看官方文档了解更多详情。
页面元素的提取
WebMagic 中使用了三种主要的数据提取技术:
使用管道保存结果
WebMagic 用来保存结果的组件称为管道。
比如我们通过“控制台输出”做的事情,也是通过一个内置的Pipeline来完成的,这个Pipeline叫做ConsolePipeline。
那么,我现在想把结果保存成Json格式,怎么做呢?
我只需要将 Pipeline 的实现替换为“JsonFilePipeline”即可。
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从"https://github.com/code4craft"开始抓
.addUrl("https://github.com/code4craft")
.addPipeline(new JsonFilePipeline("./webmagic"))
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
模拟 POST 请求方法
0.7.1版以后放弃了nameValuePair的老写法,通过在Request对象中添加Method和requestBody来实现。
Request request = new Request("http://xxx/path");
request.setMethod(HttpConstant.Method.POST);
request.setRequestBody(HttpRequestBody.json("{'id':1}","utf-8"));
HttpRequestBody内置多种初始化方法,支持最常见的表单提交、json提交等方法。

java爬虫抓取动态网页(python如何检测网页中是否存在动态加载的数据?(图))
网站优化 • 优采云 发表了文章 • 0 个评论 • 49 次浏览 • 2022-01-15 23:10
在使用python爬虫技术采集数据信息时,经常会遇到在返回的网页信息中无法抓取到动态加载的可用数据。例如,当在网页中获取产品的价格时,就会出现这种现象。如下所示。本文将实现类似的动态加载数据爬取网页。
1. 那么什么是动态加载的数据呢?
我们通过requests模块爬取的数据不能每次都是可见的,部分数据是通过非浏览器地址栏中的url请求获取的。相反,通过其他请求请求的数据,然后通过其他请求请求的数据是动态加载的数据。(猜测是js代码在我们访问这个页面从其他url获取数据的时候会发送get请求)
2. 如何检测网页中是否有动态加载的数据?
在当前页面打开抓包工具,在地址栏抓到url对应的数据包,在数据包的response选项卡中搜索我们要抓取的数据。如果找到了搜索结果,说明数据不是动态加载的。否则,数据将被动态加载。如图所示:
或者右键要爬取的页面,显示网页的源代码,搜索我们要爬取的数据。如果搜索到结果,说明数据没有动态加载,否则说明数据是动态加载的。如图所示:
3. 如果数据是动态加载的,我们如何捕获动态加载的数据呢?
在实现对动态加载的数据信息的爬取时,首先需要根据动态加载技术在浏览器的网络监控器中选择网络请求的类型,然后对预览信息中的关键数据进行一一过滤查询,得到对应请求地址,最后解析信息。具体步骤如下:
在浏览器中,按快捷键F12打开开发者工具,然后选择Network(网络监视器),在网络类型中选择JS,然后按快捷键F5刷新,如下图。
在请求信息列表中,依次点击各个请求信息,然后在对应的Preview(请求结果预览)中查看是否是需要获取的动态加载的数据,如下图所示。
查看动态加载的数据信息后,点击Headers获取当前网络请求地址和所需参数,如下图所示。
根据上述步骤得到的请求地址,发出网络请求,从返回的信息中提取商品价格信息。作者在代码中使用了反序列化。关于json序列化和反序列化,可以点这里学习。代码如下:
import requests
import json
# 获取商品价格的请求地址
url = "https://c0.3.cn/stock?skuId=12464037&cat=1713,3259,3333&venderId=1000077923&area" \
"=4_113_9786_0&buyNum=1&choseSuitSkuIds=&extraParam={%22originid%22:%221%22}&ch=1&fqsp=0&" \
"pduid=1573698619147398205303&pdpin=jd_635f3b795bb1c&coord=&detailedAdd=&callback=jQuery6495921"
jQuery_id = url.split("=")[-1] + "("
# 头部信息
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
}
# 发送网络请求
response = requests.get(url, headers=headers)
if response.status_code == 200:
goods_dict = json.loads(response.text.replace(jQuery_id, "")[:-1]) # 反序列化
print(f"当前售价为: {goods_dict['stock']['jdPrice']['op']}")
print(f"定价为: {goods_dict['stock']['jdPrice']['m']}")
print(f"会员价为: {goods_dict['stock']['jdPrice']['tpp']}")
else:
print("请求失败!")
作者在写博文的时候,价格发生了变化,运行结果如下图所示:
注意:爬取动态加载的数据信息时,需要根据不同的网页使用不同的方法提取数据。如果运行源码时出现错误,请按照步骤获取新的请求地址。
至此,这篇关于Python实现网页中动态加载数据爬取的文章文章就介绍到这里了。更多关于Python爬取网页动态数据的信息,请搜索我们之前的文章或继续浏览下面的相关文章希望大家以后多多支持! 查看全部
java爬虫抓取动态网页(python如何检测网页中是否存在动态加载的数据?(图))
在使用python爬虫技术采集数据信息时,经常会遇到在返回的网页信息中无法抓取到动态加载的可用数据。例如,当在网页中获取产品的价格时,就会出现这种现象。如下所示。本文将实现类似的动态加载数据爬取网页。

1. 那么什么是动态加载的数据呢?
我们通过requests模块爬取的数据不能每次都是可见的,部分数据是通过非浏览器地址栏中的url请求获取的。相反,通过其他请求请求的数据,然后通过其他请求请求的数据是动态加载的数据。(猜测是js代码在我们访问这个页面从其他url获取数据的时候会发送get请求)
2. 如何检测网页中是否有动态加载的数据?
在当前页面打开抓包工具,在地址栏抓到url对应的数据包,在数据包的response选项卡中搜索我们要抓取的数据。如果找到了搜索结果,说明数据不是动态加载的。否则,数据将被动态加载。如图所示:

或者右键要爬取的页面,显示网页的源代码,搜索我们要爬取的数据。如果搜索到结果,说明数据没有动态加载,否则说明数据是动态加载的。如图所示:

3. 如果数据是动态加载的,我们如何捕获动态加载的数据呢?
在实现对动态加载的数据信息的爬取时,首先需要根据动态加载技术在浏览器的网络监控器中选择网络请求的类型,然后对预览信息中的关键数据进行一一过滤查询,得到对应请求地址,最后解析信息。具体步骤如下:
在浏览器中,按快捷键F12打开开发者工具,然后选择Network(网络监视器),在网络类型中选择JS,然后按快捷键F5刷新,如下图。

在请求信息列表中,依次点击各个请求信息,然后在对应的Preview(请求结果预览)中查看是否是需要获取的动态加载的数据,如下图所示。

查看动态加载的数据信息后,点击Headers获取当前网络请求地址和所需参数,如下图所示。

根据上述步骤得到的请求地址,发出网络请求,从返回的信息中提取商品价格信息。作者在代码中使用了反序列化。关于json序列化和反序列化,可以点这里学习。代码如下:
import requests
import json
# 获取商品价格的请求地址
url = "https://c0.3.cn/stock?skuId=12464037&cat=1713,3259,3333&venderId=1000077923&area" \
"=4_113_9786_0&buyNum=1&choseSuitSkuIds=&extraParam={%22originid%22:%221%22}&ch=1&fqsp=0&" \
"pduid=1573698619147398205303&pdpin=jd_635f3b795bb1c&coord=&detailedAdd=&callback=jQuery6495921"
jQuery_id = url.split("=")[-1] + "("
# 头部信息
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
}
# 发送网络请求
response = requests.get(url, headers=headers)
if response.status_code == 200:
goods_dict = json.loads(response.text.replace(jQuery_id, "")[:-1]) # 反序列化
print(f"当前售价为: {goods_dict['stock']['jdPrice']['op']}")
print(f"定价为: {goods_dict['stock']['jdPrice']['m']}")
print(f"会员价为: {goods_dict['stock']['jdPrice']['tpp']}")
else:
print("请求失败!")
作者在写博文的时候,价格发生了变化,运行结果如下图所示:

注意:爬取动态加载的数据信息时,需要根据不同的网页使用不同的方法提取数据。如果运行源码时出现错误,请按照步骤获取新的请求地址。
至此,这篇关于Python实现网页中动态加载数据爬取的文章文章就介绍到这里了。更多关于Python爬取网页动态数据的信息,请搜索我们之前的文章或继续浏览下面的相关文章希望大家以后多多支持!
java爬虫抓取动态网页(java爬虫抓取动态网页的视频和文档原代码在【利用java实现哔哩视频爬虫】)
网站优化 • 优采云 发表了文章 • 0 个评论 • 52 次浏览 • 2022-01-15 01:01
java爬虫抓取动态网页的视频和文档原代码在【利用java实现哔哩哔哩视频爬虫】
我个人建议是直接用threadpoolexecutor或者futuretask吧,基本框架不用选择httpclient,而是rxjava。
进入mybatis(深入理解spring)-in-1.html,
动态网页采集看楼主的说明,应该是你现在做的jsp页面不是java所能处理的,html和css要优化才能做动态。建议:既然是用springmvc+ejb+jpa来处理网页,
万能插件:threadpoolexecutor。没有它怎么可以说动态的java爬虫。以上是demo,
动态网页很难做,java并不能处理这些网页。
做java网页也还是要在jsp下写呢吧。用ejb或者mybatis吧。
spring+ejb+mybatis,
threadpoolexecutor和jboss动态网页也是可以的。根据题主的要求,应该是需要代理服务器来处理http请求。
看在哪些web应用场景了,代理服务器为proxy-sideproxy,proxy-sideproxy是自动插入路由器的端口映射,然后发起http连接。如果你是要替换为google的服务,需要注意,他们的http接口没有模拟socket,http本身支持异步,一般用c++封装成socket的框架使用,如web框架glassfish-c++插件。
如果替换成其他常用web服务器,如tomcat/iis,建议用,反序列化使用objectsocket(和tcp一样的功能,但是是一次响应),注意是在路由器上处理,不是客户端,服务器端和客户端的通信,双方都是有可能会丢失重复。使用完了就切到自己的内部路由上。以上看下这个,那些场景下可以比较快,你可以在开始学习的时候,分类查找,很重要。 查看全部
java爬虫抓取动态网页(java爬虫抓取动态网页的视频和文档原代码在【利用java实现哔哩视频爬虫】)
java爬虫抓取动态网页的视频和文档原代码在【利用java实现哔哩哔哩视频爬虫】
我个人建议是直接用threadpoolexecutor或者futuretask吧,基本框架不用选择httpclient,而是rxjava。
进入mybatis(深入理解spring)-in-1.html,
动态网页采集看楼主的说明,应该是你现在做的jsp页面不是java所能处理的,html和css要优化才能做动态。建议:既然是用springmvc+ejb+jpa来处理网页,
万能插件:threadpoolexecutor。没有它怎么可以说动态的java爬虫。以上是demo,
动态网页很难做,java并不能处理这些网页。
做java网页也还是要在jsp下写呢吧。用ejb或者mybatis吧。
spring+ejb+mybatis,
threadpoolexecutor和jboss动态网页也是可以的。根据题主的要求,应该是需要代理服务器来处理http请求。
看在哪些web应用场景了,代理服务器为proxy-sideproxy,proxy-sideproxy是自动插入路由器的端口映射,然后发起http连接。如果你是要替换为google的服务,需要注意,他们的http接口没有模拟socket,http本身支持异步,一般用c++封装成socket的框架使用,如web框架glassfish-c++插件。
如果替换成其他常用web服务器,如tomcat/iis,建议用,反序列化使用objectsocket(和tcp一样的功能,但是是一次响应),注意是在路由器上处理,不是客户端,服务器端和客户端的通信,双方都是有可能会丢失重复。使用完了就切到自己的内部路由上。以上看下这个,那些场景下可以比较快,你可以在开始学习的时候,分类查找,很重要。