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小时内与您取得联系。