基于python构建搜索引擎系列——(二)网络爬虫

Gypsophila

发布日期: 2019-05-28 20:16:43 浏览量: 698
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

网络爬虫又称网络蜘蛛、Web采集器等,它是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。

我们在设计网络爬虫的时候需要注意两点:

  • 鲁棒性:Web中有些服务器会制造采集器陷阱(spider traps),这些陷阱服务器实际上是Web页面的生成器,它能在某个域下生成无数网页,从而使采集器陷入到一个无限的采集循环中去。采集器必须能从这些陷阱中跳出来。当然,这些陷阱倒不一定都是恶意的,有时可能是网站设计疏忽所导致的结果

  • 礼貌性:Web服务器具有一些隐式或显式的政策来控制采集器访问它们的频率。设计采集器时必须要遵守这些代表礼貌性的访问政策

采集器的基本架构如下图所示。

基本上是”抓取→分析→得到新的URL→再抓取→再分析”这样一个死循环过程。

以上内容摘自王斌老师翻译的《信息检索导论》课本。

由于我们要做的是一个新闻搜索引擎,所以抓取的是新闻数据,对于爬虫,网上也有很多的开源程序,如nutch等,Github上还有人专门开发了抓取新闻的组件newspaper,可以很方便的提取新闻标题、正文、时间等信息。不过用python写爬虫也是分分钟的事情,下面我们一起来试一试。

首先找一个新闻网站,为简单起见,要找那种结构清晰、html代码便于解析的门户网站,比如搜狐新闻参考消息等。

搜狐新闻的国内要闻列表如下:

结构非常清楚,左边是带URL的标题,右边括号里有新闻时间。这一页列表就有200条新闻,如果我们要获取1000条,只要不断模拟点击下一页即可。下一页的URL也只是在首页的基础上加上_xxx.shtml,xxx就是不同的页码。

查看列表的html源码,得知列表都在类名为newsblue1的td中,所以只需要解析html源码就可以得到新闻标题、URL和时间,python解析html可以用BeautifulSoup包,非常方便。

进入到新闻详细页面,正文部分如下:

查看html源码,正文位于类名为text clear的div中,据此可以很方便的提取新闻正文。

得到一条新闻的所有数据之后,我们需要将之结构化成xml文件,借助相应的xml包可以很方便的完成这项工作。xml格式定义如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <doc>
  3. <id></id>
  4. <url></url>
  5. <title></title>
  6. <datetime></datetime>
  7. <body></body>
  8. </doc>

注意爬虫需要访问网络,难免会出现一些异常,所以捕获异常是非常有必要的。另外,搜狐每篇新闻正文后面都会有一段’//‘开始的注释,这个需要过滤掉,短于140个字的新闻我也过滤掉了。整个搜索系统的配置参数都存储在config.ini文件中。

下面是完整的python 3.4+代码:

  1. from bs4 import BeautifulSoup
  2. import urllib.request
  3. import xml.etree.ElementTree as ET
  4. import configparser
  5. def get_news_pool(root, start, end):
  6. news_pool = []
  7. for i in range(start,end,-1):
  8. page_url = ''
  9. if i != start:
  10. page_url = root +'_%d.shtml'%(i)
  11. else:
  12. page_url = root + '.shtml'
  13. try:
  14. response = urllib.request.urlopen(page_url)
  15. except Exception as e:
  16. print("-----%s: %s-----"%(type(e), page_url))
  17. continue
  18. html = response.read()
  19. soup = BeautifulSoup(html)
  20. td = soup.find('td', class_ = "newsblue1")
  21. a = td.find_all('a')
  22. span = td.find_all('span')
  23. for i in range(len(a)):
  24. date_time = span[i].string
  25. url = a[i].get('href')
  26. title = a[i].string
  27. news_info = ['2016-'+date_time[1:3]+'-'+date_time[4:-1]+':00',url,title]
  28. news_pool.append(news_info)
  29. return(news_pool)
  30. def crawl_news(news_pool, min_body_len, doc_dir_path, doc_encoding):
  31. i = 1
  32. for news in news_pool:
  33. try:
  34. response = urllib.request.urlopen(news[1])
  35. except Exception as e:
  36. print("-----%s: %s-----"%(type(e), news[1]))
  37. continue
  38. html = response.read()
  39. soup = BeautifulSoup(html)
  40. try:
  41. body = soup.find('div', class_ = "text clear").find('div').get_text()
  42. except Exception as e:
  43. print("-----%s: %s-----"%(type(e), news[1]))
  44. continue
  45. if '//' in body:
  46. body = body[:body.index('//')]
  47. body = body.replace(" ", "")
  48. if len(body) <= min_body_len:
  49. continue
  50. doc = ET.Element("doc")
  51. ET.SubElement(doc, "id").text = "%d"%(i)
  52. ET.SubElement(doc, "url").text = news[1]
  53. ET.SubElement(doc, "title").text = news[2]
  54. ET.SubElement(doc, "datetime").text = news[0]
  55. ET.SubElement(doc, "body").text = body
  56. tree = ET.ElementTree(doc)
  57. tree.write(doc_dir_path + "%d.xml"%(i), encoding = doc_encoding, xml_declaration = True)
  58. i += 1
  59. if __name__ == '__main__':
  60. config = configparser.ConfigParser()
  61. config.read('../config.ini', 'utf-8')
  62. root = 'http://news.sohu.com/1/0903/61/subject212846158'
  63. news_pool = get_news_pool(root, 854, 849)
  64. crawl_news(news_pool, 140, config['DEFAULT']['doc_dir_path'], config['DEFAULT']['doc_encoding'])
  65. print('done!')

本文转载自:http://bitjoy.net/2016/01/04/introduction-to-building-a-search-engine-2

上传的附件 cloud_download 新闻搜索引擎.7z ( 3.33mb, 5次下载 )

发送私信

似是而非的对白,诉说着我和你的爱

23
文章数
19
评论数
eject