基于WebMagic开源爬虫的简单应用

在业务系统中我们经常需要将来自网络中的一些信息应用到我们的系统中,那么从网络中爬取一些有价值的信息是我们经常想要用到的,如我们想要获取所有汽车品牌,车型及年代款式等信息,想要定期的获取行业内相关的资讯,某领域内专业机构发布的数据报表等。WebMagic是一个开源的爬虫项目,能够很好很便捷的帮助我们快速开发有关爬虫的功能。最近研究了下Webmagic,下面的例子使用webMagic爬取某一网站信息将内容存入mysql中。

工具

  1. Webmagic 0.7.3
  2. mybatis 3.4.2

编写自定义的 PageProcessor

我们将首先我们创建Maven Project。在我们的pom.xml文件中引入

<dependency>
	<groupId>us.codecraft</groupId>
	<artifactId>webmagic-core</artifactId>
	<version>0.7.3</version>
</dependency>
<dependency>
	<groupId>us.codecraft</groupId>
	<artifactId>webmagic-extension</artifactId>
	<version>0.7.3</version>
</dependency>

要写一个爬虫使用WebMagic,核心的东西是PageProcessor的编写,而我们定制的PageProcessor则要包含爬虫的配置、页面元素的抽取和链接的发现。

public class ScripturePageProcessor implements PageProcessor {
	private ApplicationContext context;
	private ScriptureService scriptureService;

	// 爬虫配置
	//private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);

	public ScripturePageProcessor() {
	    //引入应用程序配置
	    context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
	}

    private Site site = Site.me().setCycleRetryTimes(5).setRetryTimes(5).setSleepTime(500).setTimeOut(3 * 60 * 1000)
            .setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0")
            .addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
            .addHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3")
            .setCharset("GB2312");

     /**
     * 信息提取及保存
     */
    public void process(Page page) {
        //抓取后续要处理的链接
        List<String> relativeUrl = page.getHtml().xpath("//td/a[@target='content']/@href").all();
        page.addTargetRequests(relativeUrl);
        
        if(relativeUrl.size()==0){
            //抓取后续要处理的链接
            relativeUrl = page.getHtml().xpath("//td/div[@align='center']/a/@href").all();
            page.addTargetRequests(relativeUrl);
            //卷
            String volume = page.getHtml().xpath("//body/span[@class='top']/text()").toString();
            //章
            String chapter = page.getHtml().xpath("//table/tbody/tr/td[@colspan='4' and @valign='TOP']/div/font[@size='+2' and @color='red']/text()").toString();
            
            List<String> sentenceSections =  page.getHtml().xpath("//table/tbody/tr").all();
            for(String strContent:sentenceSections){
    	        //节
            	String section= new Html(strContent).xpath("//td[@class='ver']/text()").toString();
            	String sentence=null;
            	if(section!=null){
            		//内容
            		sentence= new Html(strContent).xpath("//td[@class='txt']/text()").toString();
            		//写入数据库
            		scriptureService = (ScriptureService) context.getBean("scriptureService");
                	Scripture entity = new Scripture();
                	entity.setVolume(volume);
                	entity.setChapter(chapter);
            		entity.setSection(Integer.valueOf(section));
            		entity.setSentence(sentence.replace(" ", "").replace(" ", ""));
                	entity.setUrl(page.getUrl().get());
                	scriptureService.insert(entity);
            	}
            }
        }
    }

    public Site getSite() {
        return site;
    }

    public static void main(String[] args) {
        Spider.create(new ScripturePageProcessor()).
                addUrl("http://******").
                addPipeline(new JsonFilePipeline("D:\\Webmagic\\")).
                //thread(5).
                run();
    }
}

好了,就这么简单,这样一个简单的爬虫就可以运行了。
1. page.addTargetRequests(relativeUrl); 用来保存发现的后续需要处理的链接,
2. page.getHtml().xpath() 用来获取当前页面中的元素,可以通过元素样式等属性来进行查找元素。

接下来是我们用于存储到数据库中的service以及mapper了,mybatis会帮助我们持久化到mysql中。

@Service
public class ScriptureService {
    @Autowired
    private ScriptureMapper scriptureMapper;
    public int insert(Scripture scripture){
        return scriptureMapper.insert(scripture);
    }
}

public interface ScriptureMapper {
    int insert(Scripture scripture);
}

Pom.xml完整配置

在我们的Pom.xml文件中引入需要的包,我们的配置是这样的:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.story</groupId>
	<artifactId>story-webmagic</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	
	<properties>
		<us-codecraft-version>0.7.3</us-codecraft-version>
		<spring-framework-version>4.3.6.RELEASE</spring-framework-version>
		<commons-dbcp-version>1.2.2</commons-dbcp-version>
		
		<mybatis-version>3.4.2</mybatis-version>
		<mybatis-spring-version>1.3.1</mybatis-spring-version>
		<mysql-connector-java-version>5.1.30</mysql-connector-java-version>
	</properties>
	
	<dependencies>
		<!-- webmagic -->
		<dependency>
			<groupId>us.codecraft</groupId>
			<artifactId>webmagic-core</artifactId>
			<version>${us-codecraft-version}</version>
		</dependency>
		<dependency>
			<groupId>us.codecraft</groupId>
			<artifactId>webmagic-extension</artifactId>
			<version>${us-codecraft-version}</version>
		</dependency>
		<!-- spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring-framework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring-framework-version}</version>
		</dependency>
		<!-- mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>${mybatis-version}</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>${mybatis-spring-version}</version>
		</dependency>
		<!-- mysql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql-connector-java-version}</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>${commons-dbcp-version}</version>
		</dependency>
		<!-- log4j -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
	</dependencies>
</project>

我们的应用程序配置 applicationContext.xml 如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <!-- 加载配置文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <context:component-scan base-package="com.story.webmagic"/>

    <!-- 数据源,使用dbcp -->     
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url.confidential}" />
        <property name="username" value="${jdbc.user.confidential}" />
        <property name="password" value="${jdbc.password}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${jdbc.initialSize}"></property>
        <!-- 连接池最大数量 -->
        <property name="maxActive" value="${jdbc.maxActive}"></property>
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${jdbc.maxIdle}"></property>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${jdbc.minIdle}"></property>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${jdbc.maxWait}"></property>
    </bean>

    <!-- sqlSessionFactory -->
    <bean id = "sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource"></property>
        <!-- 省略手动注册mybatis的sql文件**.xml,直接在resource/mapper/下找所有sql的xml文件 -->
        <property name="mapperLocations" value="classpath:/mapper/*.xml"></property>
        <!-- 加载mybatis的配置文件 -->
        <property name="configLocation" value="mybatis-config.xml"></property>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.story.webmagic" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

    <bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

增加mybatis的配置文件 mybatis-config.xml。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
</configuration>

最后增加数据库配置 jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url.confidential=jdbc:mysql://localhost:3306/story_web
jdbc.user.confidential=root
jdbc.password=snj1987

jdbc.initialSize=0
jdbc.maxActive=20
jdbc.maxIdle=20
jdbc.minIdle=1
jdbc.maxWait=60000

这是一个简单的例子,可以看到抓取信息是如此的简单。省去了我们自己写爬虫,要模拟http请求,解析等的过程,这些步骤已经全部被封装好了,我们只需要拿来使用就可以了,帮助文档非常的详细,看官方给的例子也更容易上手。

参考资料:

  1. WebMagic项目地址
  2. WebMagic帮助文档

发表评论

电子邮件地址不会被公开。 必填项已用*标注