【网络爬虫】给关键字获取百度知道搜索数据的网络爬虫
转载请注明出处:http://blog.csdn.net/qq_26525215
本文源自【大学之旅_谙忆的博客】
简单的通过关键字,爬出百度知道的一些搜索数据。
例如:问题,提问时间;答案文本,答案时间,点赞数,拍砖数,回答人,回答人级别,搜索的关键字等。
答案可以有多个,每个问题有多个答案应都保存。保存数据在MySql中。
在这里需要用到一个牛人的爬虫框架:
WebMagic
网址:http://webmagic.io/docs/zh/
我用的是IEDA工具,建立的是Maven项目。
要搞爬虫,一些基础的学习是不可少的,比如HTML,JSP等前台知识,知道怎么解析xml文档(利用XPath),用开发工具(推荐Intellij IDEA),MySQL,Maven也可以学习等等。
下面就开始讲怎么抓取百度知道的数据了。
我们用百度知道搜索的时候,可以看地址栏:
https://zhidao.baidu.com/search?ct=17&pn=0&tn=ikaslist&rn=10&word=%E7%A4%BE%E4%BF%9D%E8%BD%AC%E7%A7%BB&fr=wwwt
这里关键词的变量名是word。那么其他变量与值可以不用管它。
缩减一下地址:
https://zhidao.baidu.com/search?word=社保迁移
还有重要的一点是,百度知道的html的编码是GBK的!注意编码不要搞错了。
这个时候我们就可以利用这个地址来进行一些事情了。
需要学会用浏览器查看网页源码哦。
通过这种方式,我们可以找出标题的规律,进而通过XPath解析,得到标题名!
这些数据(标题,问题描述,答案,时间等)都是可以通过上面方式得到的!
这里有个小问题,就是点赞数和拍砖数这样是找不到正确的方式的,因为那里是动态生成。
在这里做一个演示:
通过火狐浏览器的查看元素源码,是这样的。
通过在地址栏前面加: view-source: 可以看网页源码。
一般点击鼠标右键,可以直接看网页源码。
这个时候,我们并不可以在源码中看到刚刚的代码。
也就是说,我们抓取网页的源码的时候,获取到的html也是没有那个的,怎么办,这个时候,我们会发现,
<span alog-action="qb-zan-btnbestbox" class="iknow-qb_home_icons evaluate evaluate-32" id="evaluate-2225390772" data-evaluate="7" >
</span>
data-evaluate=”7”
正好与点赞数7一样!
继续对比一下其他页面,会发现这个属性的值就是点赞数!
那么好办了,通过XPath然后加工一下,一样可以获取此值。
拍砖数一样的分析,然后获取就行!
至于其他的数据,差不多都是这样分析的。
开始本来想做成Web应用,结果WebMagic爬虫框架只能在main线程才能运行,所以就只做了一个简单的用main函数启动的应用了。
用到了MyBatis和Spring。主要是为了操作数据库简单一点。
你可以不用框架的,主要代码只有这个类的代码:
package cn.hncu;import cn.hncu.model.Answer;
import cn.hncu.model.Keyword;
import cn.hncu.model.KeywordProblemKey;
import cn.hncu.model.Problem;
import cn.hncu.service.KeywordService;
import cn.hncu.service.KeywordServiceImpl;
import cn.hncu.tool.*;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;import javax.xml.xpath.XPath;
import java.io.IOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.*;/*** Created with IntelliJ IDEA.* User: 陈浩翔.* Date: 2017/2/27.* Time: 下午 6:29.* Explain:*/
public class Entrance implements PageProcessor {private Logger logger = LoggerFactory.getLogger(Entrance.class);private static ApplicationContext context;private static KeywordService keywordService;//搜索的关键字private static String keyword = "社保转移";//百度知道的搜索前缀private static String url = "https://zhidao.baidu.com/search?word=";//设置抓取页数private static Integer pages = 20;private Site site = Site.me().setCharset("gbk").setRetrySleepTime(4).setSleepTime(100);private static String keywordId ;private List<Map<String,String>> lists;@Overridepublic void process(Page page) {Html html = page.getHtml();//问题String problem = html.xpath("//span[@class='ask-title']/text()").toString();logger.info("问题:"+problem);//提问者String problemAnthor = html.xpath("//a[@alog-action='qb-ask-uname']/text()").toString();//logger.info("提问者:"+problemAnthor);//问题描述String problemDescribe = html.xpath("//span[@class='con']/text()").toString();//logger.info("问题描述:"+problemDescribe);//提问时间if(problem==null) {lists = new ArrayList<Map<String, String>>();List<String> strs = html.xpath("//dd/span[@class='mr-8']/text()").all();List<String> quizTimes = new ArrayList<String>();for (int i=0;i<strs.size();i++) {//logger.info(strs.get(i)+" "+strs.get(i).matches("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"));if(strs.get(i).matches("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]")){quizTimes.add(strs.get(i));}}List<String> portionProblems = html.xpath("//a[@class='ti']/text()").all();//logger.info("quizTimes.size():" + quizTimes.size());//logger.info("portionProblems.size():" + portionProblems.size());if(quizTimes.size()==portionProblems.size()) {for (int i=0;i<quizTimes.size();i++) {Map<String,String> map = new HashMap<String,String>();map.put("quizTimes",quizTimes.get(i));map.put("portionProblems",portionProblems.get(i));lists.add(map);//logger.info("部分问题:" + lists.get(i).get("portionProblems"));//logger.info("时间:" + lists.get(i).get("quizTimes"));}}}//最佳回答String bestAnswer =html.xpath("//pre[@class='best-text mb-10']").toString();//图片文字无法处理if(bestAnswer==null){bestAnswer =html.xpath("//div[@class='best-text mb-10']").toString();}//logger.info("最佳回答:"+bestAnswer);//回答者String answerAuthor = html.xpath("//a[@class='mavin-name f-14 mr-10']/text()").toString();//如果回答者为NULL-有可能是其他的没有认证的人回答的if(answerAuthor==null){answerAuthor = html.xpath("//div[@class='grid f-aid ff-arial']/p/a[@class='user-name']/text()").toString();}//如果回答者还是为NULL-有可能是网上的人贡献的if(answerAuthor==null){answerAuthor = html.xpath("//div[@class='grid f-aid ff-arial']/p[@class='mb-5']/span/text()").toString();}//logger.info("回答者:"+answerAuthor);//回答者等级String anthorGrade = html.xpath("//a[@class='mavin-reply-icon f-orange']/text()").toString();//如果回答者等级为NULL-有可能是其他的没有认证的人回答的if(anthorGrade==null){anthorGrade = html.xpath("//div[@class='grid f-aid ff-arial']/p[@class='mb-5']/a[@class='i-gradeIndex']").toString();if(anthorGrade!=null){anthorGrade = "LV"+anthorGrade.substring(anthorGrade.lastIndexOf("Index-")+6,anthorGrade.lastIndexOf(" mr-10"));}}if(answerAuthor!=null&&anthorGrade==null){anthorGrade ="0";}//logger.info("回答者等级:"+anthorGrade);//推荐时间String answerTime = html.xpath("//span[@class='grid-r f-aid pos-time answer-time f-pening']/text()").toString();//logger.info("推荐时间:"+answerTime);//最佳回答点赞数String pointPraise =html.xpath("//span[@alog-action='qb-zan-btnbestbox']").toString();if(pointPraise!=null) {pointPraise = pointPraise.substring(pointPraise.lastIndexOf("evaluate")).replaceAll("evaluate=\"", "").replaceAll("\"> </span>", "");}//logger.info("最佳回答点赞数:"+pointPraise);//最佳回答拍砖数String contemptNumber =html.xpath("//span[@alog-action='qb-evaluate-outer']").toString();if(contemptNumber!=null) {contemptNumber = contemptNumber.substring(contemptNumber.lastIndexOf("evaluate")).replaceAll("evaluate=\"", "").replaceAll("\"> </span>", "");}//logger.info("最佳回答拍砖数:"+contemptNumber);//将发布时间和问题放到一块去,这里需要匹配String quizTimes = null;//这个判断有漏洞的!!!if(problem!=null) {for (int i = 0; i < lists.size(); i++) {String portionProblem = lists.get(i).get("portionProblems");String time = lists.get(i).get("quizTimes");boolean isThisProblem = true;for (int j = 0; j < portionProblem.length(); j++) {if(problem.indexOf(portionProblem.charAt(j))==-1){isThisProblem = false;}}if(isThisProblem){quizTimes = time;continue;}}}//发表时间//logger.info("发表时间:"+quizTimes);//其他回答答案List<String> otherAnswers =html.xpath("//div[@class='answer-text']/span").all();//logger.info("其他回答答案:"+otherAnswers);//其他回答的回答时间List<String> otherAnswerTime =html.xpath("//div[@class='grid pt-5']/span[@class='pos-time']/text()").all();//logger.info("其他回答的回答时间:"+otherAnswerTime);//其他回答的回答者List<String> otherAnswerAnthors =html.xpath("//a[@alog-action='qb-username' and @class='user-name']/text()").all();//logger.info("其他回答的回答者:"+otherAnswerAnthors);//其他回答的回答者等级List<String> otherAnswerAnthorGradesLists =html.xpath("//div[@class='grid pt-5']/span[@class='i-gradeIndex']").all();List<String> otherAnswerAnthorGrades = new ArrayList<String>();if(otherAnswerAnthorGradesLists!=null){for(int i=0;i<otherAnswerAnthorGradesLists.size();i++){otherAnswerAnthorGrades.add("LV"+otherAnswerAnthorGradesLists.get(i).substring(otherAnswerAnthorGradesLists.get(i).lastIndexOf("Index-")+6,otherAnswerAnthorGradesLists.get(i).lastIndexOf("\"></span>")));}}//logger.info("其他回答的回答者等级:"+otherAnswerAnthorGrades);//其他回答的点赞数List<String> otherAnswerPointPraiseLists =html.xpath("//span[@alog-action='qb-zan-btn']").all();List<String> otherAnswerPointPraises = new ArrayList<String>();if(otherAnswerPointPraiseLists!=null) {for(int i=0;i<otherAnswerPointPraiseLists.size();i++) {otherAnswerPointPraises.add(otherAnswerPointPraiseLists.get(i).substring(otherAnswerPointPraiseLists.get(i).lastIndexOf("evaluate")).replaceAll("evaluate=\"", "").replaceAll("\"> </span>", ""));}}//logger.info("其他回答的点赞数:"+otherAnswerPointPraises);//其他回答的拍砖数List<String> otherAnswerContemptNumberLists =html.xpath("//div[@class='pos-relative']/div[@class='qb-zan-eva']/span[@alog-action='qb-evaluate-outer']").all();List<String> otherAnswerContemptNumbers = new ArrayList<String>();if(otherAnswerContemptNumberLists!=null) {for(int i=0;i<otherAnswerContemptNumberLists.size();i++) {otherAnswerContemptNumbers.add( otherAnswerContemptNumberLists.get(i).substring(otherAnswerContemptNumberLists.get(i).lastIndexOf("evaluate")).replaceAll("evaluate=\"", "").replaceAll("\"> </span>", ""));}}//logger.info("其他回答的拍砖数:"+otherAnswerContemptNumbers);//如果为了效率,可以开线程去存数据的if(answerAuthor!=null || otherAnswers.size()!=0){//问题表数据Problem p = new Problem();String problemId = cn.hncu.tool.UUID.getId();p.setId(problemId);p.setProblem(problem);p.setQuizTime(quizTimes);p.setProblemAnthor(problemAnthor);p.setProblemDescribe(problemDescribe);//关键字—问题关系表数据KeywordProblemKey keywordProblemKey = new KeywordProblemKey();keywordProblemKey.setKeywordId(keywordId);keywordProblemKey.setProblemId(problemId);//最佳答案数据List<Answer> answers = new ArrayList<Answer>();Answer answer = new Answer();answer.setId(cn.hncu.tool.UUID.getId());answer.setProblemId(problemId);answer.setAnswerAnthor(answerAuthor);answer.setAnswer(bestAnswer);answer.setAnthorGrade(anthorGrade);answer.setPointPraise(pointPraise);answer.setAnswerTime(answerTime);answer.setContemptNumber(contemptNumber);answers.add(answer);//其他答案数据Integer otherAnswersSize = otherAnswers.size();for(int i=0;i<otherAnswersSize;i++){answer = new Answer();answer.setId(cn.hncu.tool.UUID.getId());answer.setProblemId(problemId);if(otherAnswerAnthors.size()>i)answer.setAnswerAnthor(otherAnswerAnthors.get(i));if(otherAnswers.size()>i)answer.setAnswer(otherAnswers.get(i));if(otherAnswerAnthorGrades.size()>i)answer.setAnthorGrade(otherAnswerAnthorGrades.get(i));if(otherAnswerPointPraises.size()>i)answer.setPointPraise(otherAnswerPointPraises.get(i));if(otherAnswerTime.size()>i)answer.setAnswerTime(otherAnswerTime.get(i));if(otherAnswerContemptNumbers.size()>i)answer.setContemptNumber(otherAnswerContemptNumbers.get(i));answers.add(answer);}keywordService.insertAll(p,keywordProblemKey,answers);}
// if (page.getResultItems().get("name") == null) {
// //skip this page
// page.setSkip(true);
// }// 从搜索页面发现后续的url地址来抓取
// List<String> urls = html.links().regex("(http://zhidao.baidu.com/question/.+"+"\\?"+".+[^\"])").all();
// for(String url:urls){
// logger.info(url);
// }if(problem==null) {page.addTargetRequests(html.links().regex("(http://zhidao.baidu.com/question/.+"+"\\?"+".+[^\"])").all());for(int i=1;i<pages;i++){List<String> lists = new ArrayList<String>();lists.add(url+keyword+"&site=-1&sites=0&date=0&pn="+(i*10));page.addTargetRequests(lists);}pages=0;//只加一次进队列!}}@Overridepublic Site getSite() {return site;}public static void main(String[] args) throws IOException {//使用"spring.xml"和"spring-mybatis.xml"这两个配置文件创建Spring上下文context = new ClassPathXmlApplicationContext("spring.xml", "spring-mybatis.xml");keywordService = (KeywordService) context.getBean("keywordService");//存储关键字表Date searchTime = new Date();//搜索的时间keywordId = cn.hncu.tool.UUID.getId();Keyword keyword = new Keyword();keyword.setId(keywordId);keyword.setKeyword(Entrance.keyword);keyword.setSearchTime(searchTime);keywordService.insertKeyword(keyword);Spider.create(new Entrance()).addUrl(url+Entrance.keyword)//.addPipeline(new JsonFilePipeline("D:\\test\\"))//开启 *个线程抓取.thread(50)//同步启动爬虫.run();}
}
数据库很简单,看你自己需要哪些数据,就建立哪些字段和表就行。
建立MySQL数据表的文件在项目的src/main/resources/sql/1.sql
本篇博客涉及到的源码链接:
【->点击访问源码-©CHX】
本文章由[谙忆]编写, 所有权利保留。
欢迎转载,分享是进步的源泉。
转载请注明出处:http://blog.csdn.net/qq_26525215
本文源自【大学之旅_谙忆的博客】
【网络爬虫】给关键字获取百度知道搜索数据的网络爬虫相关推荐
- 从零开始写Python爬虫 --- 1.5 爬虫实践: 获取百度贴吧内容
从零开始写Python爬虫 --- 1.5 爬虫实践: 获取百度贴吧内容 Ehco 5 个月前 经过前期大量的学习与准备,我们重要要开始写第一个真正意义上的爬虫了.本次我们要爬取的网站是:百度贴吧,一 ...
- 企业网络推广时网站获取排名离不开企业网络推广文章内容的更新
搜索引擎在抓取网站排名时,网站内容价值性的体现瞬间放大,与此同时,网站内容更新频率也是不容小觑的.对于企业网站运营优化期间,不同类型的企业网站可以选择不同的内容更新频率,那么怎样针对企业网站制定合理的 ...
- 【爬虫】Python2爬虫代码之获取金融品种行情数据
Python2爬虫代码之获取金融品种行情数据 #!/usr/bin/env python # -*- coding: utf-8 -*- import requests #使用requests包方便 ...
- python 爬虫 获取bilibili search搜索数据,返回json格式
话不多说直接上代码 测试用例 : 搜索java为关键词的 时长在60分钟以上的视频 import requests import json import osheaders = {"user ...
- 百度头条改版了?发一个最新获取百度头条新闻数据
百度热点新闻改版导致获取失效了,重新写了一版 , 注意是热点榜数据 <?php //获取百度热点榜新闻 header('content-type:application/json'); echo ...
- 学习记录:python GoPUP获取百度指数动态数据对比看国人野性消费
前言 前几天看公众号,看到一篇文章利用GoPUP获取百度指数,做鸿星尔克崛起的数据对比感觉挺有意思的,参考一下文章也来玩玩学习学习 原文:http删除我s://m删除我p.we删除我ixin.q删除我 ...
- Python爬虫实践: 获取百度贴吧内容
最近开始整理python的资料,博主建立了一个qq群,希望给大家提供一个交流的平台 78486745 . 我们要爬取的网站是:百度贴吧,一个非常适合新人练手的地方,那么让我们开始吧. 本次要爬的贴吧是 ...
- 【爬虫】爬取百度贴吧数据
在这里我们写一个简单的小爬虫程序,爬取百度贴吧前几页的数据. import requests import sysclass Tieba(object): def __init__(self, nam ...
- 【爬虫实践】获取某城市天气数据
功能需求 获取山东济南城市每天的天气情况. 需要获取四个数据:天气.温度.风向.风级. url地址:http://www.weather.com.cn/weather/101120101.shtml ...
最新文章
- Why平台:Scalable是互联网公司的价值所在
- Java IO: Buffered和Data
- 成功解决AttributeError: module tensorflow.sets has no attribute intersection
- ajax请求php的过程,php如何实现ajax请求
- VS2005水晶报表发布
- 反射调用 java bean的set和get方法
- Apache JK Tomcat 集群问题
- php validator classes
- Anroid camera + mediacodec
- 广数系统980tdb系统说明书_不同数控系统中各个倒角指令的用法
- 通信原理第七版樊昌信 课后习题答案详解
- python评分卡模型
- php编程怎样装数据库,php数据库管理工具phpmyadmin下载、安装、配置
- 百果园港交所上市:市值近百亿港元 80%营收来自加盟店
- ZiSync:跨平台局域网自同步工具
- linux的日志处理之Logrotate
- C#读取txt日志文件
- 为响应国家减税,SAP增值税如何调整 ?
- 如何在Adobe Illustrator中创建青蛙王子插图
- 3ds Max 2024新特性及安装图文教程