爬虫——我爱手语网

爬虫程序需要掌握的几个知识:

1、首先需要使用XPath对网页进行下载和解析,需要导入htmlcleaner.jar包,去官网下载即可。

2、需要了解网页元素定位方式,当然谷歌浏览器自带开发者工具,直接选中需要定位的部分,右键选中检查或者Ctrl+Shift+I即可进行定位,定位好的html代码右键选中copy-->Copy XPath,即可生成xpath语法。

目前遇到的问题:

1、能够爬取定位好的某一个元素,但是换成/td之后的所有子元素之后,爬取的对象会拼接成一条字符串,将每一个元素分离出来需要写额外的代码,希望可以通过Object[]对象数组在爬取时就进行分离,但是编译无法通过,报越界问题,原因是一个元素也没存入。

2、手语网中的词汇描述和词汇是放在一个td之中的,通过换行符<br>将其分割,目前无法分别提取出词汇和词汇描述,只能将整个<td>之中的内容提取出来。

3、手语网中有很多分类,每个分类之中又有很多分页,所有需要全部存入数据库,需要编写更换url的代码。

解决办法:

1、通过对Xpath的学习和理解,了解了Xpath的语法,之前直接定位检查某一小块的html代码,然后复制xpth语法相应的只能爬取该小块的内容,所以我们需要自己写Xpath语法。

通过逐个定位手语网的结构,了解到网页是由两个大的table构成,第一个存分类,第二个存这类的词汇,而第二个table中又有很多table,用于存储单条信息,诸如词汇描述图片。分析完成之后,操作方法就是分两步爬取,第一步爬取第二个table中的所有table条目,存储类型为Object[]:

Object[] obje = tn.evaluateXPath("//*[@id=\"main_content\"]/table/tbody/tr/td[2]/table");

第二步对于获取到的每一个table对象进行解析,即拆出词汇、描述、图片网址;

if(obje!=null&&obje.length>0) {
    	for(Object obj:obje) {
    		TagNode tntr = (TagNode) obj;
    		String vocabulary=tntr.evaluateXPath("//tbody/tr/td/table/tbody/tr/td[1]/a/strong/text()")[0].toString();
    		String description=tntr.evaluateXPath("//tbody/tr/td/table/tbody/tr/td[1]/text()")[0].toString();
    		String path=tntr.evaluateXPath("//tbody/tr/td/table/tbody/tr/td[2]/img/@src")[0].toString();
    	}
    }

到此就可以爬取该页的所有信息。

2、暂时没有好的解决方法,没有能够通过<br>进行定位的语法,有说通过.xpath('string(.)')来解决,试过不行;python貌似可以做的:

tips_lst = []
lst = page.xpath('//div/div')
#提取 1、荷兰豆汆烫变色即可,千万不要过火,时间也就是几秒钟。
print lst[0].text
#依次提取 2, 3, 4
lst = page.xpath('//div/div[@class="tip"]/br')
for ll in lst:
    print ll.tail

 3、目前打算通过将分类爬取出来存储,然后逐个循环获取每一页的最大页数,然后通过修改url中的分类和页码进行全站爬取。

类似这种/称谓_1__shouyul/、/职务_2__shouyul/。

实际实现的时候遇到了一个莫名其妙的问题:我在获取每一个分类中的最大页码时使用的是类似这样的语句(因为最后最后一项是“尾页”,所以要爬取倒数第二项,而且不能直接申明单个Object对象,要声明为数组,否则TagNode n = (TagNode) last;会报错)

Object last[] = tn.evaluateXPath("//*[@id=\"main_content\"]/table/tbody/tr/td[2]/div/a[last()-1]");

问题是当我直接使用last()时,打印结果显示正常为“尾页”,使用last()+1时,打印输出“首页",使用last()-1时则报如下错误

java.lang.ArrayIndexOutOfBoundsException: 0

个人觉得时last()-n无法使用的,所以换成了稍微复杂的思路,即将手语网中的分页中的a标签全部获取,然后读取对象数组的大小减1即为最大页码的值:

部分代码如下:

Object[]  page= tn.evaluateXPath("//*[@id=\"main_content\"]/table/tbody/tr/td[2]/div/a");
    int n=page.length-1;
    if(n>0) {
    	for(int i=1;i<=n;i++) {
    		new SpiderMain().getSpiderData("https://shouyu.51240.com/"+classify+"_"+i+"__shouyul/");
    	}
    }

4、对于数据库的问题仍旧有,当我们没有设置默认的数据库编码格式为utf8时,无法插入汉字,utf8的设置为ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

以及当我们在使用insert和update的语法时,我们应该用statement的stat.execute()方法,而不是rs.executeQuery()的方法;否则会报错Can not issue data manipulation statements with executeQuery()。

代码部分:

下载html内容

package com.demo;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

public class DownloadHtml {

/**
 * 下载指定URL的Html内容
 * @param url url连接
 * @return 返回html页面内容
 * @throws Exception 
 */
public String getHtml(String url) throws Exception{

    URL u = new URL(url);

    URLConnection  conn =u.openConnection();
    InputStream in = conn.getInputStream();

    BufferedReader br = new BufferedReader(new InputStreamReader(in));

    String line = null;
    StringBuffer html = new StringBuffer();
    while((line=br.readLine())!=null){
        html.append(line);
    }

    in.close();
    br.close();
    return html.toString();
}

}

Xpath解析

package com.demo;

import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;

public class SpiderMain {
/**
 * 爬虫解析方法
 * @param url  待采集的URL
 * @return 返回解析的内容
 * @throws Exception
 */
public void getSpiderData(String url) throws Exception{

    //1.下载html
    String html = new DownloadHtml().getHtml(url);

    HtmlCleaner hc = new HtmlCleaner();
    //2.把html转换成dom对象
    TagNode tn = hc.clean(html);
    //3.通过xpath解析dom对象
    Object[] obje = tn.evaluateXPath("//*[@id=\"main_content\"]/table/tbody/tr/td[2]/table");
    if(obje!=null&&obje.length>0) {
    	for(Object obj:obje) {
    		TagNode tntr = (TagNode) obj;
    		String vocabulary=tntr.evaluateXPath("//tbody/tr/td/table/tbody/tr/td[1]/a/strong/text()")[0].toString();
    		String description=tntr.evaluateXPath("//tbody/tr/td/table/tbody/tr/td[1]/text()")[0].toString();
    		String path=tntr.evaluateXPath("//tbody/tr/td/table/tbody/tr/td[2]/img/@src")[0].toString();
    		System.out.println(vocabulary+"   "+description+"   "+path);
    		
    		new Shouyu().put(vocabulary, description, path);
    	}
    }
}
public static void main(String[] args) {	
     try {
         new SpiderMain().getSpiderData("https://shouyu.51240.com/称谓_1__shouyul/");
     } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}
}

数据库sql语法:

package com.demo;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Shouyu {
      public void put(String vocabulary,String description,String path) {
    	  String sql="insert into shouyu(vocabulary,description,path)values("
    			  +"'"+vocabulary+"','"+description+"','"+path+"');";
    	  Statement stat=null;
  		  ResultSet rs=null;
  		Connection conn=new DBHelper().getConn();
  		try {
  			stat = conn.createStatement();
  			stat.execute(sql);
  			}catch(SQLException e) {
  				e.printStackTrace();
  			}
  			finally {
  				try {
  					if(conn!=null) {
  						conn.close();
  					}
  					if(stat!=null) {
  						stat.close();
  					}
  					if(rs!=null) {
  						rs.close();
  					}
  				}catch(SQLException ex) {
  					ex.printStackTrace();
  				}
  			}
  		}
  	

      }

数据库连接池

package com.demo;

import java.sql.*;

public class DBHelper {	
	String url ="jdbc:mysql://localhost/test?user=root&password=hya8&useUnicod"+ //严格定义,jdbc之后的:也不能少
	"e=true&amp;characterEncoding=utf-8" ; 
	String jdbcName="com.mysql.jdbc.Driver";//驱动程式的名字,是统一的
	public Connection getConn(){//connection是一个接口,在java。sql下,用于生成一个连接数据库对象
		Connection conn = null;
		try{
			Class.forName(jdbcName);//将mysql驱动注册到DriverManager中去
		}
		catch(Exception e){}
		try{
			conn= DriverManager.getConnection(url); //获得连接对象
		}
		catch(SQLException ex){}
		return conn;		
	}
	
	public static void main(String[] args)
	{
		System.out.println(new DBHelper().getConn());
		
	}
	
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值