案例简述
主要通过简单的对HTML网页源码分析和对urllib库的简单使用,实现从网页上爬取【文本类型】数据,如本案例当中的爬取笔趣阁小说。
注意点:
- 本案例只适合网页爬取文本数据的简单练习,不适合实战应用;
- 本案例没有解决访问频率过于频繁,被爬取网站会限制ip的问题;
- 针对访问频率频繁问题,本案例采用的是通过延长访问的间隔时间来避免;
- 本案例的数据存储为本地txt文本文档存储
实现原理
- 访问电子书的目录页面,通过分析页面源代码,通过re正则表达式匹配内容,来爬取电子书的章节文本和章节链接;
- 分别访问对应的章节链接,继续分析页面源代码,通过re正则表达式匹配内容,爬取电子书的正文文本;
- 存储到本地文本文档中。
源代码
import gzip import random import re import time import urllib.request import urllib from urllib3.packages.six import BytesIO # 笔趣阁小说http://www.biquge.info/ def getNovelList_biquge(): # text_url = input('请输入电子书网页:') # 该链接为笔趣阁《遮天》的访问链接 text_url = 'http://www.biquge.info/10_10233/' # 由于读取的源码是压缩过的十六进制的形式,所以需要转换格式 html = urllib.request.urlopen(text_url).read() bytes_html = BytesIO(html) html = gzip.GzipFile(fileobj=bytes_html).read().decode('utf-8') # 匹配例子<dd><a href="5103237.html" title="写在连载前">写在连载前</a></dd> # 匹配章节的链接,获取链接集合,获取小说名字 html_reg = r'<dd><a href="(.*?)" title=".*?">(.*?)</a></dd>' title_reg = r'<h1>(.*?)</h1>' html_reg = re.compile(html_reg) title_reg = re.compile(title_reg) html_urls = re.findall(html_reg, html) title = re.findall(title_reg, html) # 章节长度 text_count = len(html_urls) # 当前爬取章节数 current = 0 # 单独处理每个章节的链接 for content_url in html_urls: time.sleep(random.randint(5, 10)) # 章节链接 chapter_url = content_url[0] # 章节名字 chapter_name = content_url[1] # 获取章节链接源码,转换utf-8格式 chapter_html = urllib.request.urlopen(text_url + chapter_url).read() # urlopen读取的链接格式不同,所以分两种方式转码 if chr(chapter_html[1]) == '!': chapter_html = chapter_html.decode('utf-8') else: chapter_bytes = BytesIO(chapter_html) chapter_html = gzip.GzipFile(fileobj=chapter_bytes).read().decode('utf-8') # re匹配正文格式 chapter_reg = r' (.*?)<br/><br/>' chapter_reg = re.compile(chapter_reg, re.S) # 获取正文的集合 context_list = re.findall(chapter_reg, chapter_html) f = open('{}.txt'.format(title[0]), 'a', encoding='utf-8') # 写入章节名称 f.write(chapter_name + '\r\n') # 将获取的章节正文写入TXT文本 for context in context_list: f.write(context + '\r\n') f.close() # 用来判断进度 current += 1 print(str(current) + '/' + str(text_count)) print("爬取完成") getNovelList_biquge()
问题总结
Q1:在使用urlopen访问链接并读取页面的源代码时,可能会出现【读取到不同的编码格式】的情况,如出现【全部为16进制字符】或【HTML源代码夹杂16进制字符】的情况。
A1:
【全部为16进制字符】的转码
chapter_bytes = BytesIO(chapter_html) chapter_html = gzip.GzipFile(fileobj=chapter_bytes).read().decode('utf-8')【HTML源代码夹杂16进制字符】
chapter_html = chapter_html.decode('utf-8')
Q2:在写入本地TXT文本时,可能会因为读取的页面上的一些特殊字符,导致出现【UnicodeEncodeError: 'gbk' codec can't encode character '\u30fb'】的情况。
A2:
处理方式一(较麻烦):直接去除这些特殊字符(无用),再写入本地文本
t = re.compile('[^A-Z^a-z^0-9^\u4e00-\u9fa5]') # 将获取的章节正文写入TXT文本 for context in context_list: context = t.sub('', context) f.write(context + '\r\n') f.close()
*注意点:此处直接去除了所有的字符,只保留了英文、中文、数字。
处理方式二(推荐):设置写入的编码格式为‘utf-8’,因为Windows默认新文件的编码格式为‘gbk’
f = open('{}.txt'.format('测试文本'), 'a', encoding='utf-8')*注意点:如果文件出现乱码,先删除原本的文本,然后重新运行程序。