采集网站内容(互联网上搜索引擎可以抓到的那部分网络都是深网)
优采云 发布时间: 2022-03-21 21:23采集网站内容(互联网上搜索引擎可以抓到的那部分网络都是深网)
前言:
网络爬虫被称为网络爬虫,因为它们沿着网络爬行。它们的本质是一种递归方式。为了找到一个URL链接,他们必须先获取网页的内容,检查页面的内容,寻找另一个URL,然后获取该URL对应的网页内容,重复上述过程。
1 遍历单个域名
示例:编写一段 Python 代码,获取 Wikipedia 网站 的任意页面并提取该页面的链接
1from urllib.request import urlopen
2from bs4 import BeautifulSoup
3
4html = urlopen("http://en.wikipedia.org/wiki/Kevin_Bacon")
5bsObj = BeautifulSoup(html)
6for link in bsObj.findAll("a"):
7 if 'href' in link.attrs:
8 print(link.attrs['href'])
9
观察生成的链接列表,你会发现“入口链接”和“其他链接”的区别,你会发现“入口链接”有三个共同点:
我们可以使用这些规则稍微调整代码以获得术语链接:
1for link in bsObj.find("div", {"id":"bodyContent"}).findAll("a",href=re.compile("^(/wiki/)((?!:).)*$")):
2 if 'href' in link.attrs:
3 print(link.attrs['href'])
4
为了改进它,该实现在 网站 上实现了从一个链接到另一个链接的随机跳转:
1from urllib.request import urlopen
2from bs4 import BeautifulSoup
3import datetime
4import random
5import re
6
7random.seed(datetime.datetime.now())
8def getLinks(articleUrl):
9 html = urlopen("http://en.wikipedia.org"+articleUrl)
10 bsObj = BeautifulSoup(html)
11 return bsObj.find("div", {"id":"bodyContent"}).findAll("a",href=re.compile("^(/wiki/)((?!:).)*$"))
12
13links = getLinks("/wiki/Kevin_Bacon")
14while len(links) > 0:
15 newArticle = links[random.randint(0, len(links)-1)].attrs["href"]
16 print(newArticle)
17 links = getLinks(newArticle)
18
2 采集整个网站
[$]补充:网站有深网、暗网、浅网。与表面网相反,深层网是网的一部分。浅网是可以抓取的互联网搜索引擎
到网络的那个部分。据不完全统计,大约90%的互联网实际上是深网。暗网,也称为暗网或暗网,完全是另一个“怪物”。它们也建立在现有网络之上,但使用 Tor 客户端和运行在 HTTP 之上的新协议,为信息交换提供安全隧道。
网站采集的一个常见且耗时的方法是从一个顶级页面(例如首页)开始,然后搜索页面上的所有链接,形成一个列表。再次转到 采集 这些链接中的每一个,然后形成每个页面上找到的链接的新列表,重复下一轮 采集。
[*]注意:为了避免一个页面被采集两次,链接去重非常重要。
1from urllib.request import urlopen
2from bs4 import BeautifulSoup
3import re
4
5pages = set()
6def getLinks(pageUrl):
7 global pages
8 html = urlopen("http://en.wikipedia.org"+pageUrl)
9 bsObj = BeautifulSoup(html)
10 for link in bsObj.findAll("a", href=re.compile("^(/wiki/)")):
11 if 'href' in link.attrs:
12 if link.attrs['href'] not in pages:
13 # 我们遇到了新页面
14 newPage = link.attrs['href']
15 print(newPage)
16 pages.add(newPage)
17 getLinks(newPage)
18getLinks("")
19
[*] 注意:如果递归运行次数过多,之前的递归程序很可能会崩溃。
Python 的默认递归限制(程序递归调用自身的次数)是 1000 次。
为了有效地使用它们,我们在使用爬虫时需要在页面上做几件事:
1from urllib.request import urlopen
2from bs4 import BeautifulSoup
3import re
4
5pages = set()
6def getLinks(pageUrl):
7 global pages
8 html = urlopen("http://en.wikipedia.org"+pageUrl)
9 bsObj = BeautifulSoup(html)
10 try:
11 print(bsObj.h1.get_text())
12 print(bsObj.find(id="mw-content-text").findAll("p")[0])
13 print(bsObj.find(id="ca-edit").find("span").find("a").attrs['href'])
14 except AttributeError:
15 print("页面缺少一些属性!不过不用担心!")
16
17 for link in bsObj.findAll("a", href=re.compile("^(/wiki/)")):
18 ...#与上面一样
19
3 通过互联网采集
在编写爬虫以随意跟踪外部链接之前,请先问自己几个问题:
几个灵活的 Python 函数可以组合起来实现不同类型的网络爬虫,只需不超过 50 行代码即可轻松编写:
1from urllib.request import urlopen
2from bs4 import BeautifulSoup
3import re
4import datetime
5import random
6
7pages = set()
8random.seed(datetime.datetime.now())
9# 获取页面所有内链的列表
10def getInternalLinks(bsObj, includeUrl):
11 internalLinks = []
12 # 找出所有以"/"开头的链接
13 for link in bsObj.findAll("a", href=re.compile("^(/|.*"+includeUrl+")")):
14 if link.attrs['href'] is not None:
15 if link.attrs['href'] not in internalLinks:
16 internalLinks.append(link.attrs['href'])
17 return internalLinks
18
19# 获取页面所有外链的列表
20def getExternalLinks(bsObj, excludeUrl):
21 externalLinks = []
22 # 找出所有以"http"或"www"开头且不包含当前URL的链接
23 for link in bsObj.findAll("a",href=re.compile("^(http|www)((?!"+excludeUrl+").)*$")):
24 if link.attrs['href'] is not None:
25 if link.attrs['href'] not in externalLinks:
26 externalLinks.append(link.attrs['href'])
27 return externalLinks
28
29def splitAddress(address):
30 addressParts = address.replace("http://", "").split("/")
31 return addressParts
32
33def getRandomExternalLink(startingPage):
34 html = urlopen(startingPage)
35 bsObj = BeautifulSoup(html)
36 externalLinks = getExternalLinks(bsObj, splitAddress(startingPage)[0])
37 if len(externalLinks) == 0:
38 internalLinks = getInternalLinks(startingPage)
39 return getNextExternalLink(internalLinks[random.randint(0,len(internalLinks)-1)])
40 else:
41 return externalLinks[random.randint(0, len(externalLinks)-1)]
42
43def followExternalOnly(startingSite):
44 externalLink = getRandomExternalLink("http://oreilly.com")
45 print("随机外链是:"+externalLink)
46 followExternalOnly(externalLink)
47
48followExternalOnly("http://oreilly.com")
49
网站无法保证在主页上始终可以找到外部链接。这时候为了能够找到外部链接,就需要一个类似于前面案例中使用的采集方法的方法,即递归深入到一个网站,直到找到外部链接找到了,然后停止。
如果我们的目标是采集一个网站所有反向链接,并记录每个反向链接,我们可以添加以下函数:
1# 收集网站上发现的所有外链列表
2allExtLinks = set()
3allIntLinks = set()
4def getAllExternalLinks(siteUrl):
5 html = urlopen(siteUrl)
6 bsObj = BeautifulSoup(html)
7 internalLinks = getInternalLinks(bsObj,splitAddress(siteUrl)[0])
8 externalLinks = getExternalLinks(bsObj,splitAddress(siteUrl)[0])
9 for link in externalLinks:
10 if link not in allExtLinks:
11 allExtLinks.add(link)
12 print(link)
13 for link in internalLinks:
14 if link not in allIntLinks:
15 print("即将获取链接的URL是:"+link)
16 allIntLinks.add(link)
17 getAllExternalLinks(link)
18getAllExternalLinks("http://oreilly.com")
19
[*]注意:服务器端重定向,你通常不用担心。如果您使用的是 Python 3.x 版本的 urllib 库,它会自动处理重定向。
4 使用 Scrapy采集
尽管编写 Scrapy 爬虫很简单,但完成爬虫需要一些设置。要在当前目录中创建一个新的 Scrapy 项目,请执行以下代码:
$scrapy startproject wikiSpider(wikiSpider 是新项目的名称。)
1文件夹的目录结构如下所示:
2• scrapy.cfg
3 — wikiSpider
4 — __init.py__
5 — items.py
6 — pipelines.py
7 — settings.py
8 — spiders
9 — __init.py__
10
要创建蜘蛛,我们需要将 articleSpider.py 文件添加到 wikiSpider/wikiSpider/spiders/ 文件夹中。另外,在 items.py 文件中,我们需要定义一个 Article 类。items.py 文件应如下所示:
1# -*- coding: utf-8 -*-
2# Define here the models for your scraped items
3#
4# See documentation in:
5# http://doc.scrapy.org/en/latest/topics/items.html
6from scrapy import Item, Field
7class Article(Item):
8 # define the fields for your item here like:
9 # name = scrapy.Field()
10 title = Field()
11
Scrapy 中的每个 Item 对象代表 网站 上的一个页面。
在新创建的articleSpider.py文件中,编写如下代码:
1from scrapy.selector import Selector
2from scrapy import Spider
3from wikiSpider.items import Article
4
5class ArticleSpider(Spider):
6 name="article"
7 allowed_domains = ["en.wikipedia.org"]
8 start_urls = ["http://en.wikipedia.org/wiki/Main_Page","http://en.wikipedia.org/wiki/Python_%28programming_language%29"]
9
10 def parse(self, response):
11 item = Article()
12 title = response.xpath('//h1/text()')[0].extract()
13 print("Title is: "+title)
14 item['title'] = title
15 return item
16
在主 wikiSpider 目录中使用以下命令运行 ArticleSpider: $ scrapy crawl article
此行将使用文章名称 article 调用爬虫。
[$] 添加:
日志显示级别可以在Scrapy项目的setting.py文件中设置:
LOG_LEVEL = '错误'
Scrapy 日志有五个级别,按范围升序排列如下:
• 危急
• 错误
• 警告
• 调试
• 信息
如果日志级别设置为 ERROR,则只会显示 CRITICAL 和 ERROR 日志。
如果日志级别设置为 INFO,则将显示所有信息,否则相同。
日志不仅可以在终端显示,还可以输出到单独的文件中,使用如下命令:
$scrapy 爬取文章 -s LOG_FILE=wiki.log
Scrapy 支持将这些信息保存为不同的输出格式,例如 CSV、JSON 或 XML 文件格式,对应的命令如下:
$scrapy 抓取文章 -o article.csv -t csv
$scrapy 抓取文章 -oarticles.json -t json
$scrapy 抓取文章 -o article.xml -t xml
Scrapy 是处理与网络数据相关的问题的绝佳工具采集。它会自动采集所有 URL 并将它们与指定规则进行比较;确保所有 URL 都是唯一的;根据需要规范化相关 URL;并递归搜索更深的页面。