最近三年很少写博客,虽然一直从事IT行业,但更多的是管理工作,想想真有些惭愧。
最近半年,时不时业务上需要爬虫,将网页内容爬取分析,有用于AI人工智能分析,有用于大数据分析,种种应用,发现爬虫作用不小
这篇文章不是一篇教学文章,更多的是分享在爬取网页中可能会遇到的一些技术问题以及常见问题,并提供解决方案。因此更适合有一定爬虫开发经验人员阅读。
虽然本文使用Java,但这些常见问题,与所使用的开发语言无关,可更多借鉴。
常见问题一:网页的获取方式
1、直接获取静态页面方式
何为“静态页面”,指页面内容通过HTTP获取的时候,已经是完整页面内容,没有使用Ajax异步调用生成页面内容的网页,即页面内容均在后台生成。
仅对该类页面,使用基于HTTP方式直接加载页面时,才可以获取完整页面内容。
对于Java语言,可以使用JSoup或者HttpClient去抓取,页面获取效率非常高。下面提供参考源码:
JSoup方式:
- /**
- * 获取游记文章页面的HTML对象。
- *
- * @param articleUrl
- * 文章URL地址。
- * @return
- * @throws IOException
- */
- private Document getArticleDocument(String articleUrl) throws IOException {
- Connection conn = Jsoup.connect(articleUrl);
- conn.header("User-Agent",
- "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0");
- Response rs = conn.execute();
- Document doc = Jsoup.parse(rs.body());
- return doc;
- }
HttpClient方式:
- /**
- * 直接通过HTTP请求获取页面内容。
- *
- * @param url
- * @return
- * @throws ClientProtocolException
- */
- public static String getUrlHtml(String url) throws ClientProtocolException,
- IOException {
- HttpClient httpclient = HttpClientBuilder.create().build();
- HttpGet httpGet = new HttpGet(url);
- httpGet.setHeader("User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; W…) Gecko/20100101 Firefox/56.0");
- httpGet.setHeader("Accept",
- "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
- httpGet.setHeader("Accept-Language",
- "zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4");
- httpGet.setHeader("Accept-Encoding", "gzip, deflate, sdch");
- httpGet.setHeader("Upgrade-Insecure-Requests", "1");
- HttpResponse response1 = httpclient.execute(httpGet);
- HttpEntity entity = response1.getEntity();
- String html = EntityUtils.toString(entity);
- return html;
- }
HttpClient依赖:
- <dependency>
- <groupId>org.apache.httpcomponents</groupId>
- <artifactId>httpclient</artifactId>
- <version>4.5.2</version>
- </dependency>
JSoup依赖:
- <dependency>
- <!-- jsoup HTML parser library @ https://jsoup.org/ -->
- <groupId>org.jsoup</groupId>
- <artifactId>jsoup</artifactId>
- <version>1.10.3</version>
- </dependency>
- [color=red]
- 此处需要特别强调,对于很多网站,对爬虫都有一定的防范,因此在获取页面时,必须要补齐浏览器信息,否则很容易会导致被封IP!
- [/color]
2、使用模拟浏览器方式获取动态页面
使用模拟浏览器的方式实属被逼无奈,因为这种方式处理速度实在是慢,但对于异步加载内容的网页特别有效。如果你发现直接通过Http拉取页面获取不到元素值的时候,也只能使用这种方法。
HtmlUnit获取网页:
- /**
- * 通过模拟浏览器的方式下载完整页面。
- *
- * @param url
- * @return
- * @throws FailingHttpStatusCodeException
- * @throws IOException
- */
- public static String downloadHtml(String url, int timeout)
- throws FailingHttpStatusCodeException, IOException {
- try (final WebClient webClient = new WebClient(BrowserVersion.CHROME)) {
- webClient.getOptions().setJavaScriptEnabled(true);
- webClient.getOptions().setCssEnabled(false);
- webClient.getOptions().setRedirectEnabled(true);
- webClient.getOptions().setThrowExceptionOnScriptError(false);
- webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
- webClient
- .setAjaxController(new NicelyResynchronizingAjaxController());
- webClient.getOptions().setTimeout(timeout);
- WebRequest webRequest = new WebRequest(new URL(url));
- webRequest.setHttpMethod(HttpMethod.GET);
- final HtmlPage page = webClient.getPage(webRequest);
- webClient.waitForBackgroundJavaScriptStartingBefore(500);
- webClient.waitForBackgroundJavaScript(20000);
- final String pageAsXml = page.asXml();
- return pageAsXml;
- }
- }
HtmlUnit依赖:
- <dependency>
- <groupId>net.sourceforge.htmlunit</groupId>
- <artifactId>htmlunit</artifactId>
- <version>2.30</version>
- </dependency>
常见问题二:如何避免IP被封
处理方式比较简单,就是不要使用并发,或者连续性的长时间抓取网站内容。最好抓取的时候,保持一定的时间间隔,根据我抓取不同网站的经验,间隔在3-5秒获取一次网页最为保险,一些网站一旦封了IP,可能要一周左右才解锁,因此对于固定外网IP的用户,正在大规模抓取之前必须留意该限制。
以下抓取代码供参考:
- /*
- * (non-Javadoc)
- *
- * @see
- * com.hna.tech.spider.service.SpiderService#setPageArticleDetail(java.lang
- * .String)
- */
- public List<Map<String, String>> setPageArticleDetail(
- List<Map<String, String>> pageList) throws IOException,
- InterruptedException {
- for (Map<String, String> item : pageList) {
- [color=red]
- // 最小延迟3秒,少于3秒将可能被封IP
- Thread.sleep(3000);
- [/color]
- String articleUrl = item.get(KEY_LINK);
- Document doc = getArticleDocument(articleUrl);
- String articleHtml = getArticleContentHtml(doc);
- item.put(KEY_CONTENT_HTML, articleHtml);
- String articleContent = getArticleContent(doc);
- item.put(KEY_CONTENT, articleContent);
- }
- return pageList;
- }
那么如何提升抓取效率呢?一般网站,都会根据Session以及IP进行锁定是否DDOS攻击,或者恶意刷网页,所以问题也就简单了,通过多个线程发起请求,保证每个Session请求的间隔时间。另外,并发也不要太过分,只要不对网站造成压力,一般不会被封IP。
常见问题三:对于元素选取的问题
获取元素的方式有很多种方法,可以通过ID、CSS样式、元素类型(比如<a/> <p/>)等,可根据个人喜好,通常都可以获得元素的内容,比如文章标题、文章正文等等。
以下分享我个人使用JSoup获取页面元素内容的一些心得。
1、阶梯式获取
即优先优先获取顶级节点,比如<Content>是文章内容的顶级节点,那么通过JSoup先获取 第一个顶级节点,然后再获取下级节点的内容,避免当存在多个<Content>节点的时候,会出现获取内容超出预期。
2、CSS样式的选取问题
当存在多个class样式,比如:<div class="css1 css2">...</div>,使用JSoup选取:
- doc.select("div.css1.css2")
使用点号连在一起即可。
相关推荐
近年来,逐渐开放的微软加快了 Visual Studio 的演进速度,持续地吸收了不少 VA 的特性,但多年的积累使得 VA 的对应实现仍有着很强的竞争力。就拿代码重构里最基本的“重命名”来说,VA Rename 就比 VS Rename 步骤...
1)首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变 量是指向参数的指针. 2)然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第 一个可变参数的前一个参数,是一个固定的参数. 3)然后用va_arg返回...
VA_X官方下载链接:http://www.wholetomato.com/downloads/default.asp VA_X历史版本下载:http://support.wholetomato.com/default.asp?W422 2. 运行Visual Assist X 通用破解补丁程序,点击安装,重新启动VS输入...
VA 函数(variable argument function),参数个数可变函数,又称可变参数 函数。C/C++编程中,系统提供给编程人员的va 函数很少。*printf()/*scanf() 系列函数,用于输入输出时格式化字符串;exec*()系列函数,用于...
VA_X_Setup2210 + VA_X.dll破解补丁,支持2008-2017均可用。 在用户路径下找到VA_X.dll文件,使用下载的VA_X.dll文件替换即可。 在VisualStudio这个文件夹里面有与你当前安装的VS相关的文件夹,我只装了VS2015版本...
va_start、va_end、va_list的详细使用方法,对想了解的人很有帮助。
va
1\使用了TABLE CONTRL,ALV等多种控件 2\代替标准的VA01\VA02\VA03 3\使用大量动态编程技术 4\在一个程序池内集成多个事务
va_x插件
C盘搜索VA_X.dll,然后覆盖掉,就OK了。。。。。。。。。。
1\使用了TABLE CONTRL,ALV等多种控件 2\代替标准的VA01\VA02\VA03 3\使用大量动态编程技术 4\在一个程序池内集成多个事务 5\请使用webex录屏软件来播放
VA_X_2210完美支持vs2017,具体使用看压缩包内的readme
VA_X_Setup2212 vs2017可用 替换安装包内的VA_X.dll即可使用,记住关闭自动更新
派克 VA13/VA15气动方向操作控制阀pdf,派克 VA13/VA15气动方向操作控制阀
VS工具助手,VA破解版本,2005-2017所有版本通用,好用请好评谢谢。
VA_X软件;VA_X软件;VA_X软件;VA_X软件;VA_X软件;VA_X软件; 好用!!博客里有教程
VA是什么.docx
本资源VA_X 2068安装包及破解补丁。 VA_X是C++的智能提示插件,可以支持Microsoft Visual Studio 2003,Microsoft Visual Studio 2005,Visual Studio 2008,Microsoft Visual Studio 2010,Microsoft Visual Studio...
va_list原理解释,解释了关于VA_LIST的用法、VA_LIST在编译器中的处理、VA_LIST应该注意的问题、以及相关程序
vs2008辅助工具VA