Httpclient: 多层翻页网络爬虫实战(以搜房网为例)
参考:http://blog.csdn.net/qy20115549/article/details/52912532
一、创建数据表
#创建表:用来存储url地址信息
create table soufang_address
(
id varchar(255),
title varchar(255),
url varchar(255),
craw_time varchar(255)
) #创建表:用来存储房源信息
create table soufang_content
(
id varchar(255),
title varchar(255),
publishtime varchar(255),
price varchar(255),
housetype varchar(255),
acreage varchar(255),
useacreage varchar(255),
years varchar(255),
orientation varchar(255),
floor varchar(255),
structure varchar(255),
decoration varchar(255),
type varchar(255),
buildingtype varchar(255),
propertyright varchar(255),
estate varchar(255),
school varchar(255),
facilities varchar(255)
)
二、实体类
/httpClient2/src/main/java/model/Address.java
package model; public class Address {
//地址id,用于使用map区别url地址
private String addr_id;
//url
private String addr_url;
//url对应的名称
private String title;
//爬取时间,使用jdk的date生成
private String craw_time; public String getAddr_id() {
return addr_id;
} public void setAddr_id(String addr_id) {
this.addr_id = addr_id;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public String getAddr_url() {
return addr_url;
} public void setAddr_url(String addr_url) {
this.addr_url = addr_url;
} public String getCraw_time() {
return craw_time;
} public void setCraw_time(String craw_time) {
this.craw_time = craw_time;
} }
/httpClient2/src/main/java/model/Contents.java
package model; public class Contents {
private String id;
private String title;
private String publishtime;
private String price;
private String housetype;
private String acreage;
private String useacreage;
private String years;
private String orientation;
private String floor;
private String structure;
private String decoration;
private String type;
private String buildingtype;
private String propertyright;
private String estate;
private String school;
private String facilities; public String getUseacreage() {
return useacreage;
} public void setUseacreage(String useacreage) {
this.useacreage = useacreage;
} public String getId() {
return id;
} public String getPublishtime() {
return publishtime;
} public void setPublishtime(String publishtime) {
this.publishtime = publishtime;
} public void setId(String id) {
this.id = id;
} public String getPrice() {
return price;
} public void setPrice(String price) {
this.price = price;
} public String getHousetype() {
return housetype;
} public void setHousetype(String housetype) {
this.housetype = housetype;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public String getAcreage() {
return acreage;
} public void setAcreage(String acreage) {
this.acreage = acreage;
} public String getYears() {
return years;
} public void setYears(String years) {
this.years = years;
} public String getOrientation() {
return orientation;
} public void setOrientation(String orientation) {
this.orientation = orientation;
} public String getFloor() {
return floor;
} public void setFloor(String floor) {
this.floor = floor;
} public String getStructure() {
return structure;
} public void setStructure(String structure) {
this.structure = structure;
} public String getDecoration() {
return decoration;
} public void setDecoration(String decoration) {
this.decoration = decoration;
} public String getType() {
return type;
} public void setType(String type) {
this.type = type;
} public String getBuildingtype() {
return buildingtype;
} public void setBuildingtype(String buildingtype) {
this.buildingtype = buildingtype;
} public String getPropertyright() {
return propertyright;
} public void setPropertyright(String propertyright) {
this.propertyright = propertyright;
} public String getEstate() {
return estate;
} public void setEstate(String estate) {
this.estate = estate;
} public String getSchool() {
return school;
} public void setSchool(String school) {
this.school = school;
} public String getFacilities() {
return facilities;
} public void setFacilities(String facilities) {
this.facilities = facilities;
}
}
三、utils、解析类
/httpClient2/src/main/java/util/HTTPUtils.java
package util; import java.io.IOException; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.message.BasicHttpResponse;
/*
* 执行请求
* */
public class HTTPUtils {
public static HttpResponse getRawHtml(HttpClient client, String personalUrl) {
// 获取响应文件,即html,采用get方法获取响应数据
HttpGet getMethod = new HttpGet(personalUrl);
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
HttpStatus.SC_OK, "OK");
try {
// 执行get方法
response = client.execute(getMethod);
} catch (IOException e) {
e.printStackTrace(); } finally {
// getMethod.abort();
}
return response;
} }
/httpClient2/src/main/java/util/SouFangAddressFecter.java
package util; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.GzipDecompressingEntity;
import org.apache.http.util.EntityUtils; import parse.SouFangAddressParser;
import model.Address; public class SouFangAddressFecter {
public static List<Address> htmlGet(HttpClient client, String url)
throws Exception, IOException {
List<Address> AddressInfo = new ArrayList<Address>();
HttpResponse response = HTTPUtils.getRawHtml(client, url);
int StatusCode = response.getStatusLine().getStatusCode();
if (StatusCode == 200) {
// 由于此方法总是出现乱码
// String entity = EntityUtils.toString
// (response.getEntity(),"UTF-8");
// 输出实体内容,不会乱码,乱码解决。由于数据是通过zip压缩的
GzipDecompressingEntity zipRes = new GzipDecompressingEntity(
response.getEntity());
String s = EntityUtils.toString(zipRes, "gb2312");
// 解析实体内容
AddressInfo = SouFangAddressParser.getdata(s);
EntityUtils.consume(response.getEntity());
} else {
// 关闭HttpEntity的流实体
EntityUtils.consume(response.getEntity());
} return AddressInfo; } }
/httpClient2/src/main/java/parse/SouFangAddressParser.java
package parse; import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements; import model.Address; public class SouFangAddressParser {
public static List<Address> getdata(String entity) throws IOException {
List<Address> addresses = new ArrayList<Address>();
// 获取html文件
Document doc = Jsoup.parse(entity); // 获取总页数
int sumPages = Integer.parseInt(doc.select("div[class=fanye gray6]")
.select("span[class=txt]").text().replaceAll("\\D", ""));
sumPages = 2;
// 由于此网站,第一页和第二页等有重复的房源。防止有重复的id出现,这里使用map
Map<String, Integer> keyMap = new HashMap<String, Integer>();
for (int i = 1; i <= sumPages; i++) {
// 每页的url
String everyPageUrl = "http://esf.hf.fang.com/house/i3" + i;
// 直接使用Jsoup
Document document = Jsoup.connect(everyPageUrl).timeout(50000)
.userAgent("bbbb").get();
// jsoup使用正则表达式
Elements elements = document.select("dl[id~=list_D03_?]");
// 获取每一个子内容
for (Element ele : elements) {
String id = ele.select("dd[class=info rel floatr]").select("p")
.select("a").attr("href").replaceAll("/chushou/", "")
.replaceAll(".htm", "");
if (!keyMap.containsKey(id)) {
keyMap.put(id, 1);
String url = "http://esf.hf.fang.com/"
+ ele.select("dd[class=info rel floatr]")
.select("p").select("a").attr("href");
String title = ele.select("dd[class=info rel floatr]")
.select("p[class=title]").select("a").text();
Date date = new Date();
DateFormat format = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
String craw_time = format.format(date);
Address address = new Address();
address.setAddr_id(id);
address.setAddr_url(url);
address.setCraw_time(craw_time);
address.setTitle(title);
addresses.add(address);
}
}
}
return addresses;
}
}
四、操作数据库
/httpClient2/src/main/java/db/MyDataSource.java
package db; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource;
/*
* 数据库配置信息,并且使用了dbcp2
* */
public class MyDataSource {
public static DataSource getDataSource(String connectURI) {
BasicDataSource ds = new BasicDataSource();
// MySQL的jdbc驱动
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUsername("root"); // 所要连接的数据库名
ds.setPassword("123456"); // MySQL的登陆密码
ds.setUrl(connectURI);
return ds;
}
}
/httpClient2/src/main/java/db/MYSQLControl.java
package db; import java.sql.SQLException;
import java.util.List; import javax.sql.DataSource; import model.Address;
import model.Contents; import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; public class MYSQLControl {
static final Log logger = LogFactory.getLog(MYSQLControl.class);
// 根据自己的数据库地址修改
static DataSource ds = MyDataSource
.getDataSource("jdbc:mysql://127.0.0.1:3306/moviedata");
static QueryRunner qr = new QueryRunner(ds); /*
* 查询数据的方法
*/
public static <T> List<T> getListInfoBySQL(String sql, Class<T> type) {
List<T> list = null;
try {
list = qr.query(sql, new BeanListHandler<T>(type));
} catch (Exception e) {
// TODO: handle exception
}
return list;
} /*
* 插入数据soufang_address
*/
public static void executeAddressUpdate(List<Address> addresses) {
// 定义一个Object数组,行列
Object[][] params = new Object[addresses.size()][4];
for (int i = 0; i < params.length; i++) {
params[i][0] = addresses.get(i).getAddr_id();
params[i][1] = addresses.get(i).getTitle();
params[i][2] = addresses.get(i).getAddr_url();
params[i][3] = addresses.get(i).getCraw_time();
}
try {
qr.batch("insert into soufang_address (id, title,url,craw_time)"
+ "values (?,?,?,?)", params);
} catch (Exception e) {
logger.error(e);
}
} /*
* 操作数据库,插入房源的详细信息
*/
public static void executeContentInsert(List<Contents> contentinfo)
throws SQLException {
Object[][] params = new Object[contentinfo.size()][18];
for (int i = 0; i < params.length; i++) {
params[i][0] = contentinfo.get(i).getId();
params[i][1] = contentinfo.get(i).getTitle();
params[i][2] = contentinfo.get(i).getPublishtime();
params[i][3] = contentinfo.get(i).getPrice();
params[i][4] = contentinfo.get(i).getHousetype();
params[i][5] = contentinfo.get(i).getAcreage();
params[i][6] = contentinfo.get(i).getUseacreage();
params[i][7] = contentinfo.get(i).getYears();
params[i][8] = contentinfo.get(i).getOrientation();
params[i][9] = contentinfo.get(i).getFloor();
params[i][10] = contentinfo.get(i).getStructure();
params[i][11] = contentinfo.get(i).getDecoration();
params[i][12] = contentinfo.get(i).getType();
params[i][13] = contentinfo.get(i).getBuildingtype();
params[i][14] = contentinfo.get(i).getPropertyright();
params[i][15] = contentinfo.get(i).getEstate();
params[i][16] = contentinfo.get(i).getSchool();
params[i][17] = contentinfo.get(i).getFacilities();
}
try {
qr.batch(
"insert into soufang_content (id, title,publishtime, price,housetype,acreage,useacreage,years,orientation,floor,structure,decoration,type,buildingtype,propertyright,estate,school,facilities)"
+ "values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
params);
System.out.println("共插入:\t" + contentinfo.size() + "条数据!");
} catch (Exception e) {
logger.error(e);
} }
}
五、主函数
/httpClient2/src/main/java/main/SouFangAddress.java
package main; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import model.Address; import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient; import db.MYSQLControl;
import util.SouFangAddressFecter; public class SouFangAddress {
public static void main(String[] args) throws IOException, Exception {
HttpClient client = new DefaultHttpClient();
// 初始化地址
String _url = "http://esf.hf.fang.com/";
List<Address> addresses = new ArrayList<Address>();
// 调用函数,爬取数据
addresses = SouFangAddressFecter.htmlGet(client, _url);
// 操作数据库,将获取的数据插入数据库
MYSQLControl.executeAddressUpdate(addresses);
}
}
六、总结
1、爬虫如何实现翻页:搜房网的地址比较规则,地址拼接即可
2、网络爬虫如何解决主键重复问题,在写网络爬虫时,我们经常会遇到置顶帖。这种置顶帖在每页都有:本文使用的是map集合,判断id是否已经存在
3、 Content-Encoding :gzip。数据是经过压缩的:
要先解压流数据。 GzipDecompressingEntity zipRes = new GzipDecompressingEntity(response.getEntity());
String s = EntityUtils.toString(zipRes, "gb2312"); 4、本文只爬取了出租房的链接,并将连接信息导入到数据库中。如果想获取出租房的详细信息,则只需要从数据库一个一个取出连接,加以解析即可
Httpclient: 多层翻页网络爬虫实战(以搜房网为例)的更多相关文章
- 关于Python网络爬虫实战笔记③
Python网络爬虫实战笔记③如何下载韩寒博客文章 Python网络爬虫实战笔记③如何下载韩寒博客文章 target:下载全部的文章 1. 博客列表页面规则 也就是, http://blog.sina ...
- Python简单网络爬虫实战—下载论文名称,作者信息(下)
在Python简单网络爬虫实战—下载论文名称,作者信息(上)中,学会了get到网页内容以及在谷歌浏览器找到了需要提取的内容的数据结构,接下来记录我是如何找到所有author和title的 1.从sou ...
- python网络爬虫实战PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书
点击获取提取码:vg1y python网络爬虫实战帮助读者学习Python并开发出符合自己要求的网络爬虫.网络爬虫,又被称为网页蜘蛛,网络机器人,是一种按照一定的规则,自动地抓取互联网信息的程序或者脚 ...
- 利用Python网络爬虫爬取学校官网十条标题
利用Python网络爬虫爬取学校官网十条标题 案例代码: # __author : "J" # date : 2018-03-06 # 导入需要用到的库文件 import urll ...
- 关于Python网络爬虫实战笔记①
python网络爬虫项目实战笔记①如何下载韩寒的博客文章 python网络爬虫项目实战笔记①如何下载韩寒的博客文章 1. 打开韩寒博客列表页面 http://blog.sina.com.cn/s/ar ...
- Python网络爬虫实战:根据天猫胸罩销售数据分析中国女性胸部大小分布
本文实现一个非常有趣的项目,这个项目是关于胸罩销售数据分析的.是网络爬虫和数据分析的综合应用项目.本项目会从天猫抓取胸罩销售数据,并将这些数据保存到SQLite数据库中,然后对数据进行清洗,最后通过S ...
- (转)Python网络爬虫实战:世纪佳缘爬取近6万条数据
又是一年双十一了,不知道从什么时候开始,双十一从“光棍节”变成了“双十一购物狂欢节”,最后一个属于单身狗的节日也成功被攻陷,成为了情侣们送礼物秀恩爱的节日. 翻着安静到死寂的聊天列表,我忽然惊醒,不行 ...
- Python网络爬虫实战(一)快速入门
本系列从零开始阐述如何编写Python网络爬虫,以及网络爬虫中容易遇到的问题,比如具有反爬,加密的网站,还有爬虫拿不到数据,以及登录验证等问题,会伴随大量网站的爬虫实战来进行. 我们编写网络爬虫最主要 ...
- python网络爬虫实战之快速入门
本系列从零开始阐述如何编写Python网络爬虫,以及网络爬虫中容易遇到的问题,比如具有反爬,加密的网站,还有爬虫拿不到数据,以及登录验证等问题,会伴随大量网站的爬虫实战来进行. 我们编写网络爬虫最主要 ...
随机推荐
- 构建基于Javascript的移动web CMS——Hello,World
在一篇构建基于Javascript的移动web CMS入门--简单介绍中简单的介绍了关于墨颀CMS的一些原理,其极框架组成.于是開始接着应该说明一下这个CMS是怎样一步步搭建起来. RequireJS ...
- Python生成器定义
通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素 ...
- kubernetes滚动更新
系列目录 简介 当kubernetes集群中的某个服务需要升级时,传统的做法是,先将要更新的服务下线,业务停止后再更新版本和配置,然后重新启动并提供服务.如果业务集群规模较大时,这个工作就变成了一个挑 ...
- 使用mark-sweep算法的垃圾回收器
在我写C++代码的那些时间里,我没有写过垃圾回收器,也没有实现过自己的内存分配器,这方面的文章倒是看了不 少.比如我在写C#代码时只管new而不需要释放,我也明白有个垃圾回收器在那帮我回收那些堆上的对 ...
- 怎样使用在线Webapp生成器生成安装包
在这篇文章中,我们来介绍怎样使用在线(online)的Webapp生成器来生产在Ubuntu手机或模拟器中能够安装的click安装包. Webapp生成器的地址:https://developer.u ...
- EasyDarwin开源平台直播架构
Created with Raphaël 2.1.0ClientClientEasyCMSEasyCMSEasyCameraEasyCameraEasyDarwinEasyDarwin请求设备列表设备 ...
- the algebra of modulo-2 sums disk failure recovery
x=y x_+_y=0 The bit in any position is the modulo-2 sum of all the bits in the corresponding positio ...
- No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=i386).错误解决方法
targets ->build setting 下的 Build Active Architecture Only 设置 NO 就可以.
- Mac下通过命令行安装npm install -g 报错,如何解决?
1, 使用 sudo npm install -g n2, 或者 sudo chmod -R 777 /usr/local/lib,然后 npm install -g
- MongoDB学习笔记(2):数据库操作及CURD初步
MongoDB学习笔记(2):数据库操作及CURD 数据库操作 创建数据库 首先MongoDB中数据库的创建和数据库的切换都是使用命令,USE DATABASE,如果要切换的数据库不存在则会进行创建, ...