AO数据访问
package dao;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import utils.JdbcUtils;
import utils.PageBean;
import entity.Muli;
public class MuliDao {
// 创建QueryRunner对象
private QueryRunner qr = JdbcUtils.getQueryRuner();
// 查找全部信息列表
public List<Muli> listMuliAll() {
String sql = "SELECT * FROM mulihuji ";
try {
// 多行数据,封装成对象的集合
List<Muli> listmuli = qr.query(sql, new BeanListHandler<Muli>(Muli.class));
return listmuli;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 分页显示全部数据
public void listMuliAll(PageBean<Muli> pb,Muli muli) throws SQLException {
String countsql = "select count(*) from mulihuji where 1=1";
String sql = "select * from mulihuji where 1=1";
List<Object> params = new ArrayList<Object>();
// 添加查询条件
String xm = muli.getXm();
if (xm != null && xm != "") {
countsql += " and xm like ?";
sql += " and xm like ?";
params.add("%" + xm + "%");
}
String sfzh = muli.getSfzh();
if (sfzh != null && sfzh != "") {
countsql += " and sfzh like ?";
sql += " and sfzh like ?";
params.add("%" + sfzh + "%");
}
//得到总记录数
Long count = qr.query(countsql, new ScalarHandler<Long>(),params.toArray());
pb.setTotalCount(count.intValue());
/*
* 问题: jsp页面,如果当前页为首页,再点击上一页报错! 如果当前页为末页,再点下一页显示有问题! 解决: 1. 如果当前页 <= 0;
* 当前页设置当前页为1; 2. 如果当前页 > 最大页数; 当前页设置为最大页数
*/
// 判断
if (pb.getCurrentPage() <= 0) {
pb.setCurrentPage(1); // 把当前页设置为1
} else if (pb.getCurrentPage() > pb.getTotalPage()) {
pb.setCurrentPage(pb.getTotalPage()); // 把当前页设置为最大页数
}
// 1. 获取当前页: 计算查询的起始行、返回的行数
int currentPage = pb.getCurrentPage();
int index = (currentPage - 1) * pb.getPageCount(); // 查询的起始行
int pagecount = pb.getPageCount(); // 每页的行数
sql += " limit ?,?";
params.add(index);
params.add(pagecount);
List<Muli> pageData = qr.query(sql, new BeanListHandler<Muli>(Muli.class),params.toArray() ); //获取一页的数据
// 设置到pb对象中
pb.setPageData(pageData);
}
}
Servlet设计
package servlet;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import dao.MuliDao;
import entity.Muli;
import utils.PageBean;
/**
* Servlet implementation class QueryListMuliServlet
*/
@WebServlet("/querymuli")
public class QueryListMuliServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
String xm = request.getParameter("xm");
String sfzh = request.getParameter("sfzh");
//实例化实体类并赋值
Muli muli=new Muli();
muli.setXm(xm);
muli.setSfzh(sfzh);
//1. 获取“当前页”参数; (第一次访问当前页为null)
String currPage = request.getParameter("currentPage");
// 判断
if (currPage == null || "".equals(currPage.trim())){
currPage = "1"; // 若第一次访问,设置当前页为1;
}
// 转换为整数型
int currentPage = Integer.parseInt(currPage);
//实例化pageben类
PageBean<Muli> pb = new PageBean<Muli>();
pb.setCurrentPage(currentPage);
try {
//调用数据访问的方法,传递两个参数
MuliDao mulidao = new MuliDao();
mulidao.listMuliAll(pb,muli);
request.setAttribute("pageBean", pb);
request.getRequestDispatcher("/querylist.jsp").forward(request, response);
return;
} catch (SQLException e) {
e.printStackTrace();
request.setAttribute("errorMsg", e.getMessage());
}
request.getRequestDispatcher("/error.jsp").forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
JSP页面:分为两个页面,1.提交查询条件,2.返回查询结果
期,应客户要求,采集一个旧后台管理系统中的数据列表,并将数据详情保存为HTML文件,旧平台架构为.NET 4.0+easyui,数据列为GridView,这个任务的难点是GridView分页数据抓取的问题,因为切换分页的时候,浏览器的URL是无变化的,包括HTTP请求头部、请求参数、请求URL全是一样,采用常规的方式抓取肯定是行不通的(只能采集到第一页的数据),下面看看我是如何获取分页数据。
废话不多说,直接上代码:
我是基于BeautifulSoup+requests+python3.7实现数据的抓取;
首先设置头部信息,用于保证会话和授权:
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/8.0; .NET4.0C; .NET4.0E)',
'Accept': 'text/html, application/xhtml+xml, image/jxr, */*',
'Content-Type': 'application/x-www-form-urlencoded',
'Accept-Language': 'zh-CN',
'Host': '浏览器F12,根据实际情况填写',
'Cache-Control': 'no-cache',
'Referer': '浏览器F12,根据实际情况填写',
'Cookie': 'ASP.NET_SessionId=浏览器F12,根据实际情况填写'
}
封装网络请求:
def postRequest(url, encoding='utf8', pageno=1):
data = {
'__EVENTTARGET': 'DataPager1',
'__EVENTARGUMENT': f'{pageno}',
'__LASTFOCUS': '',
'GridView1_gesoft_hidScrollOffset': '0,0',
'__VIEWSTATEENCRYPTED': '',
'__VIEWSTATE':'这个必须要填写,否则实现不了分页查询数据',
'__EVENTVALIDATION': '可选,尽量填上',
'HidAddInspectID': '',
'SCAccept$ValueField': '48:105,110,99,108,117,100,101::97,110,100:115,116,114,105,110,103',
'DataPager1_input': f'{pageno}',
'DataPager1$pageSizeList': '10',
'DdlAuthorYear': 'ALL'
}
retryFlag = True
while retryFlag:
retryFlag = False
try:
response = requests.post(url=url, data=data, headers=headers, timeout=10)
response.encoding = encoding
return response
except Exception as e:
print(f'postRequest error({url}) ', e)
retryFlag = True
time.sleep(5)
上述代码中“__VIEWSTATE”参数配置是核心中的核心,这个数据怎么获取呢,我是通过Wireshark抓包工具获取,如下图所示:
请求参数如图所示
为了提高数据采集的稳定性,网络请求增加了超时重试机制。另外特别提醒,请求一定要设置超时时间,否则会导致任务阻塞。
好了,核心部分已经讲完,至于采集到的数据如何用BeautifulSoup进行处理,大家自行在网上查找相关资料,比较简单就不再赘述了。
列表显示数据时,分页显示是必不可少的功能,活不多说,直接干货拿走,django提供了一个分页器Paginator,下面的例子说明如何使用它。
1,写一个带分页功能的查询方法
编辑 myweb\web\views.py文件,加入如下代码
from models import Tasks
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.views.decorators import csrf
#任务列表
def task_list(request):
contact_list = Tasks.objects.all().order_by('-task_start_date')
#每页显示25条
paginator = Paginator(contact_list, 25)
page = request.GET.get('page')
try:
contacts = paginator.page(page)
except PageNotAnInteger:
contacts = paginator.page(1)
except EmptyPage:
contacts = paginator.page(paginator.num_pages)
return render(request, 'taskList.html', {'contacts': contacts})
这里是将数据返回到前端页面 taskList.html页面。
2,前端页面获取并显示数据
在myweb\web\templates目录新建一个taskList.html文件,内容如下:
{% extends 'base.html' %}
{% block content %}
<table class="tableList">
<thead>
<tr>
<th>任务名称</th>
<th>操作者</th>
<th>任务描述</th>
<th>开始日期</th>
<th>结束日期</th>
<th>任务评价</th>
</tr>
</thead>
<tbody>
{% if contacts.paginator.count > 0 %}
{% for contact in contacts %}
<tr>
<td> {{ contact.task_name }} </td>
<td> {{ contact.task_user }} </td>
<td> {{ contact.task_describe }}</td>
<td> {{ contact.task_start_date }} </td>
<td> {{ contact.task_end_date }} </td>
<td> {{ contact.task_result }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="10" align="center">没有任务数据</td>
</tr>
{% endif %}
</tbody>
</table>
{# 分页HTML代码 #}
<div class="pagination">
<span class="step-links">
{% if contacts.has_previous %}
<a href="?page={{ contacts.previous_page_number }}">上一页</a>
{% endif %}
<span class="current">
Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
</span>
{% if contacts.has_next %}
<a href="?page={{ contacts.next_page_number }}">下一页</a>
{% endif %}
</span>
</div>
{% endblock %}
3,URL映射
编辑urls.py文件,加入:
url(r'^tasklist/', views.task_list),
*请认真填写需求信息,我们会在24小时内与您取得联系。