学习爬虫重要的是知识储备以及实战能力,最近有个学妹要求我帮她写一个爬虫程序,我将我编写的爬虫代码以及解释都记录下来,方便后期更多的伙伴们学习参考。
前置知识-爬虫定义
爬虫指的是一种自动化程序,用于在互联网上获取和抓取信息。它可以从网站中抓取数据并将其存储到本地计算机或其他数据库中,以便进一步处理和分析。
爬虫通常会自动访问网页、解析页面内容,并提取有用的信息,例如网页上的文本、图像、视频、音频、超链接等等。
requests 库:这是一个用于发送 HTTP 请求的库,可以发送 GET、POST、PUT、DELETE 等多种请求方式,并且可以设置请求头、请求体、Cookies 等信息。它还支持自动处理重定向、代理、SSL/TLS 等常见的网络请求问题,并且支持响应的解析,可以解析 JSON、HTML 等多种格式的响应数据。
urllib.parse 库:这是一个用于解析 URL 的库,它可以将 URL 拆分成各个部分,例如协议、域名、路径、查询参数等,并且可以对 URL 进行编码和解码,防止出现乱码和安全问题。
bs4 库:这是一个用于解析 HTML 和 XML 的库,可以从 HTML 或 XML 文件中提取数据,并且支持多种解析方式,例如基于标签名、CSS 选择器、正则表达式等。它还可以自动修正 HTML 或 XML 代码中的错误,方便数据提取。
正文-简单实现
首先,我们可以先实现一个简单的爬虫代码。
功能:
可以从指定的 URL 开始遍历整个网站。
输出网站中所有的链接。
关键代码实现:
import requests
from bs4 import BeautifulSoup
def crawl(url):
# 发送 GET 请求获取页面内容
response = requests.get(url)
# 使用 BeautifulSoup 解析页面内容
soup = BeautifulSoup(response.content, 'html.parser')
# 获取页面中所有链接
links = []
for link in soup.find_all('a'):
href = link.get('href')
if href:
links.append(href)
return links
# 测试代码
if __name__ == '__main__':
url = 'http://jshk.com.cn/mb/reg.asp?kefu=xjy'
links = crawl(url)
for link in links:
print(link)
这个代码使用了python的 requests 库来发送 HTTP 请求,使用 BeautifulSoup 库来解析 HTML 页面内容,获取页面中所有链接并输出。在测试代码中,可以指定要爬取的 URL,然后输出所有链接。
第一次优化
import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin
def get_links(url):
# 发送 GET 请求获取页面内容
response = requests.get(url)
# 使用 BeautifulSoup 解析页面内容
soup = BeautifulSoup(response.content, 'html.parser')
# 获取页面中所有链接
links = []
for link in soup.find_all('a'):
href = link.get('href')
if href:
href = urljoin(url, href) # 处理相对链接
parsed_href = urlparse(href)
if parsed_href.scheme in ('http', 'https') and parsed_href.netloc: # 只处理 http 和 https 协议的链接
links.append(href)
return links
def crawl(url, max_depth=3):
visited = set() # 已访问过的链接
queue = [(url, 0)] # 待访问的链接队列
while queue:
url, depth = queue.pop(0)
if depth > max_depth: # 超过最大深度,停止访问
break
if url not in visited:
visited.add(url)
print(' ' * depth, url)
links = get_links(url)
for link in links:
if link not in visited:
queue.append((link, depth+1))
# 测试代码
if __name__ == '__main__':
url = 'http://jshk.com.cn/mb/reg.asp?kefu=xjy'
crawl(url)
这个代码与之前的代码相比进行了以下优化:
处理相对链接:使用 urljoin 函数将相对链接转换为绝对链接,以便更好地处理。
只处理 http 和 https 协议的链接:使用 urlparse 函数获取链接的协议和域名,只处理 http 和 https 协议的链接。
控制访问深度:使用 max_depth 参数控制访问深度,避免无限递归导致程序崩溃。
优化访问效率:使用集合 visited 记录已经访问过的链接,避免重复访问。
在测试代码中,可以指定要爬取的 URL,并设置 max_depth 参数,然后输出所有链接及其对应的深度。
第二次优化
import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin
import time
class Crawler:
def __init__(self, start_url, max_depth=3, delay=1):
self.start_url = start_url
self.max_depth = max_depth
self.delay = delay
self.visited = set()
self.queue = [(start_url, 0)]
def crawl(self):
while self.queue:
url, depth = self.queue.pop(0)
if depth > self.max_depth:
break
if url in self.visited:
continue
self.visited.add(url)
print(' ' * depth, url)
time.sleep(self.delay)
links = self.get_links(url)
for link in links:
if link not in self.visited:
self.queue.append((link, depth+1))
def get_links(self, url):
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
links = []
for link in soup.find_all('a'):
href = link.get('href')
if href:
href = urljoin(url, href)
parsed_href = urlparse(href)
if parsed_href.scheme in ('http', 'https') and parsed_href.netloc:
links.append(href)
return links
# 测试代码
if __name__ == '__main__':
start_url = 'http://jshk.com.cn/mb/reg.asp?kefu=xjy'
crawler = Crawler(start_url, max_depth=3, delay=1)
crawler.crawl()
这个代码相比之前的代码进行了以下优化:
将爬虫代码封装到一个类 Crawler 中,方便控制和管理爬虫。
增加了延时参数 delay,可以设置每次访问页面的延时,避免过快访问导致被封禁。
增加了错误处理和日志记录,可以更好地处理异常情况和记录程序运行情况。
在测试代码中,可以创建一个 Crawler 对象,设置起始 URL、最大深度和延时参数,然后调用 crawl 方法开始爬取网站。其中,crawl 方法使用 BFS 算法遍历网站,get_links 方法获取页面中的所有链接,同时加入了延时和错误处理机制。
结果展示