最近几个月花时间学习了网络爬虫的基本原理及其python实现,大致了解了网络爬虫中的一些基本概念,以后有机会会陆续和大家分享我的学习过程和体会。
网络爬虫就是一个从url找到对应的页面,并从页面中解析出所需数据或新的url的过程,流程图如下:
学习网络爬虫,首先要通过系统性地读爬虫类书籍和大量阅读别人的程序了解爬虫的基本概念、基本流程及其实现、防爬策略的应对以及数据的存储和分布式爬取等问题。这些以后会逐一介绍。
最近从CSDN上看到别人写的爬取盗版小说网站上的小说的例子,个人认为这是一个比较有代表性的网络爬虫的例子,这个例子包含了编写网络爬虫的一些基本思路:发送请求获取网页、网页编码、解析网页、超时重连、数据存储、字符替换等,借此机会,自己用python实现一下,帮大家熟悉一下爬虫。
选择的网站是去看看小说网,爬取其中的小说《剑来》,就是“天不生我李淳罡,剑道万古如长夜”的那个《剑来》,从小说主页:http://www.7kankan.la/book/1/点进去即可看到小说的基本信息,我们先来分析一下网页的结构:
在这个页面中可以看到小说的全部章节目录,我们的思路是获取所有章节对应的url,然后在每个url对应的页面中找到小说正文,用到的数据结构是列表。首先,获取所有章节对应的url,并将其存入列表中:谷歌浏览器按F12后按F5,查看网页源代码,截图如下:
这里我们可以看到每个章节对应的url存放在dd标签下a标签中的href属性下,以“第一章 惊蛰”为例,我们点击第一章对应的href标签中的超链接就可以进入第一章的阅读页面,在这里我们看到第一章的真实请求地址为:
注意到每一章节被分为两个页面展示,页面的命名很规范,我们可以直接在某章节第一页url中的".html"前加上"_2"获取第二页的url,也可以通过解析网页获取第二页的url,这里我们采用第二种方式:解析“下一页”按钮获取下一页的url。
获取所有的章节名称以及每一章节中第一页和第二页对应的url并将其存入列表中,具体代码和效果如下:
#-*-coding:utf-8-*-
"""
@author:taoshouzheng
@time:2018/7/11 19:37
@email:[email protected]
"""
from urllib import request
from bs4 import BeautifulSoup
import socket
# 定义获取下一个页面的url的函数
def get_next_page_url(url):
# 定义网络状态
net_status = False
# 如果为成功获取,则一直访问,直至获取成功
while not net_status:
# 异常处理
try:
# 打开网页
response = request.urlopen(url=url, timeout=5)
# 读取网页内容,对网页进行重新编码
html = response.read().decode('gbk')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
html_soup = BeautifulSoup(html, 'html.parser')
# 找到指定的标签列表
a_list = html_soup.find_all('a', id='linkNext', class_='btn btn-default')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
a_soup = BeautifulSoup(str(a_list[0]), 'html.parser')
# 获取所需url
target_url = a_soup.a['href']
# 返回目标url
return target_url
except socket.timeout:
print('网络不稳定!')
net_status = False
# 定义获取所有url和章节名称的函数
def get_all_page_url(url):
# 定义章节列表用于存储章节
chapters_list = []
# 定义url列表用于存储url
urls_list = []
# 定义网络状态
net_status = False
# 如果为成功获取,则一直访问,直至获取成功
while not net_status:
# 异常处理
try:
# 打开网页
response = request.urlopen(url=url, timeout=5)
# 读取网页内容,对网页进行重新编码
html = response.read().decode('gbk')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
html_soup = BeautifulSoup(html, 'html.parser')
# 找到指定的标签列表
dd_list = html_soup.find_all('dd', class_='col-md-3')
# 遍历列表中的标签内容,去掉“新书感言”部分
for i in dd_list[1:]:
# 过滤掉最后两个标签
if '.html' in str(i):
# 创建BeautifulSoup对象
i_soup = BeautifulSoup(str(i), 'html.parser')
# 当前页面的url
this_url = url + str(i_soup.a['href'])
# 调用函数,获取下一个页面的url
next_url = get_next_page_url(this_url)
# 将本章节名称加入章节名称列表
chapters_list.append(i_soup.dd.a['title'] + ' 1/2')
chapters_list.append(i_soup.dd.a['title'] + ' 2/2')
# 将两个url都加入url列表
# 打印
print('成功获取url!')
urls_list.append(this_url)
urls_list.append(next_url)
# 返回章节名称列表和章节地址列表
return chapters_list, urls_list
except socket.timeout:
print('网络不稳定!')
net_status = False
# 主模块
if __name__ == "__main__":
# 目录所在的url
url = 'http://www.7kankan.la/book/1/'
# 调用函数,获取所有的章节名称和url
chapters, urls = get_all_page_url(url)
# 获取每一章节的正文内容
def parse_page(url):
# 定义网络状态
net_status = False
# 如果为成功获取,则一直访问,直至获取成功
while not net_status:
# 异常处理
try:
# 打开网页
response = request.urlopen(url=url, timeout=5)
# 读取网页内容,对网页进行重新编码
html = response.read().decode('gbk')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
html_soup = BeautifulSoup(html, 'html.parser')
# 获取第一页的正文内容列表
div_list = html_soup.find_all('div', class_='panel-body', id='htmlContent')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
div_soup = BeautifulSoup(str(div_list[0]), 'html.parser')
# 找到小说正文
current_text = div_soup.div.text
# 简单地将某些字符替换为空格
current_text = current_text.replace('一秒记住【去看看小说网 WWW.7KANKAN.LA】,更新快,无弹窗,免费读!', '')
if '-->>本章未完,点击下一页继续阅读' in current_text:
current_text = current_text.replace(' -->>本章未完,点击下一页继续阅读', '')
current_text = current_text.replace('\n', '')
# 返回网页内容
return current_text
except socket.timeout:
print('网络不稳定!')
net_status = False
可以看到在程序中我们对文本中的内容进行了简单的处理,总的代码和运行效果如下:
#-*-coding:utf-8-*-
"""
@author:taoshouzheng
@time:2018/7/11 19:37
@email:[email protected]
"""
from urllib import request
from bs4 import BeautifulSoup
import socket
# 定义获取下一个页面的url的函数
def get_next_page_url(url):
# 定义网络状态
net_status = False
# 如果为成功获取,则一直访问,直至获取成功
while not net_status:
# 异常处理
try:
# 打开网页
response = request.urlopen(url=url, timeout=5)
# 读取网页内容,对网页进行重新编码
html = response.read().decode('gbk')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
html_soup = BeautifulSoup(html, 'html.parser')
# 找到指定的标签列表
a_list = html_soup.find_all('a', id='linkNext', class_='btn btn-default')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
a_soup = BeautifulSoup(str(a_list[0]), 'html.parser')
# 获取所需url
target_url = a_soup.a['href']
# 返回目标url
return target_url
except socket.timeout:
print('网络不稳定!')
net_status = False
# 定义获取所有url和章节名称的函数
def get_all_page_url(url):
# 定义章节列表用于存储章节
chapters_list = []
# 定义url列表用于存储url
urls_list = []
# 定义网络状态
net_status = False
# 如果为成功获取,则一直访问,直至获取成功
while not net_status:
# 异常处理
try:
# 打开网页
response = request.urlopen(url=url, timeout=5)
# 读取网页内容,对网页进行重新编码
html = response.read().decode('gbk')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
html_soup = BeautifulSoup(html, 'html.parser')
# 找到指定的标签列表
dd_list = html_soup.find_all('dd', class_='col-md-3')
# 遍历列表中的标签内容,去掉“新书感言”部分
for i in dd_list[1:]:
# 过滤掉最后两个标签
if '.html' in str(i):
# 创建BeautifulSoup对象
i_soup = BeautifulSoup(str(i), 'html.parser')
# 当前页面的url
this_url = url + str(i_soup.a['href'])
# 调用函数,获取下一个页面的url
next_url = get_next_page_url(this_url)
# 将本章节名称加入章节名称列表
chapters_list.append(i_soup.dd.a['title'] + ' 1/2')
chapters_list.append(i_soup.dd.a['title'] + ' 2/2')
# 将两个url都加入url列表
# 打印
print('成功获取url!')
urls_list.append(this_url)
urls_list.append(next_url)
# 返回章节名称列表和章节地址列表
return chapters_list, urls_list
except socket.timeout:
print('网络不稳定!')
net_status = False
# 获取每一章节的正文内容
def parse_page(url):
# 定义网络状态
net_status = False
# 如果为成功获取,则一直访问,直至获取成功
while not net_status:
# 异常处理
try:
# 打开网页
response = request.urlopen(url=url, timeout=5)
# 读取网页内容,对网页进行重新编码
html = response.read().decode('gbk')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
html_soup = BeautifulSoup(html, 'html.parser')
# 获取第一页的正文内容列表
div_list = html_soup.find_all('div', class_='panel-body', id='htmlContent')
# 创建BeautifulSoup对象,用于解析网页获取所需内容
div_soup = BeautifulSoup(str(div_list[0]), 'html.parser')
# 找到小说正文
current_text = div_soup.div.text
# 简单地将某些字符替换为空格
current_text = current_text.replace('一秒记住【去看看小说网 WWW.7KANKAN.LA】,更新快,无弹窗,免费读!', '')
if '-->>本章未完,点击下一页继续阅读' in current_text:
current_text = current_text.replace(' -->>本章未完,点击下一页继续阅读', '')
current_text = current_text.replace('\n', '')
# 返回网页内容
return current_text
except socket.timeout:
print('网络不稳定!')
net_status = False
# 主模块
if __name__ == "__main__":
# 目录所在的url
url = 'http://www.7kankan.la/book/1/'
# 调用函数,获取所有的章节名称和url
chapters, urls = get_all_page_url(url)
# 遍历
for ul in urls:
# ur的索引
ul_index = urls.index(ul)
# ul的章节名
title = chapters[ul_index]
# 本url所对应的正文内容
cu_text = parse_page(ul)
print('开始写入:' + str(chapters[ul_index]))
with open('剑来.txt', 'a', encoding='utf-8') as f_obj:
f_obj.write(str(title) + '\n')
f_obj.write(str(cu_text) + '\n\n')
print('写入完毕!')
print('小说爬取完成!')
欢迎交流,QQ:3408649893