虽然以前接触过爬虫,但是也很久没有去做过相关的编码了,正好最近有需求要收集一些图片和txt,就还是一步一个脚印,玩了一下。
本文从简单的框架开始,爬取图片和爬取txt分别进行介绍。如何访问网址,打印html,分析数据,正则匹配,文件I/O,到最后爬取数据,以及如何基础的规避网站安全系统。
新手可跟着本文的节奏同步分析,只对代码感兴趣的,可直接跳转到最后。
python3+pycharm
安装第三方库requests和urllib3,这俩可在pycharm中直接安装,很少被墙
图片网址:https://page.om.qq.com/page/OGosuxbOv7M6LKD__rB7FeSA0.
浏览器访问这个地址,然后F12,查看源码,可以发现,每张图片在iframe里有一个地址。通过正则匹配出这些地址,然后下载地址中的内容即可。
库导入
import urllib.request
import requests
import re
import os
import time
创建picture文件夹用于存放
if not os.path.exists('picture'):
os.mkdir('picture')
通过requests里的get方法访问地址,并获取html
html = 'https://page.om.qq.com/page/OGosuxbOv7M6LKD__rB7FeSA0'
url = requests.get(html)
htmlcode=url.content
将html打印到本地
pagefile = open('picture/picture.txt','wb')
pagefile.write(htmlcode)
pagefile.close()
这时就可在工程下的picture文件夹中,更直观的查看html结构
规则还是很明显的,由 preview-src=" 开头, "> 结尾,中间则为完整的链接。
reg = r'preview-src="(.+)">'
reg_img = re.compile(reg)
imglist = reg_img.findall(htmlcode.decode())
这里需要注意一下转码,因为用content获取的html为bytes格式,但是findall是针对str的。
此时可打印一下验证是否得到了所有的图片链接
urllib库request类中,urlretrieve方法可下载链接,并保存到具体路径。
对地址列表进行遍历下载,同时为防止因本地网络或者网站原因导致报错,加一个try
flag = 1
for img in imglist:
try:
urllib.request.urlretrieve(img,'picture/%d.png'%flag)
print('第%d张图片下载完成'%flag)
except:
print('第%d张图片下载异常,请稍后再试'%flag)
flag += 1
import urllib.request
import requests
import re
import os
import time
if not os.path.exists('picture'):
os.mkdir('picture')
#图片来源地址
html = 'https://page.om.qq.com/page/OGosuxbOv7M6LKD__rB7FeSA0'
#获取网页html
url = requests.get(html)
htmlcode=url.content
#将html打印到txt中
pagefile = open('picture/picture.txt','wb')
pagefile.write(htmlcode)
pagefile.close()
reg = r'preview-src="(.+)">'
reg_img = re.compile(reg)
imglist = reg_img.findall(htmlcode.decode())
#print(imglist)
time.sleep(1)
flag = 1
for img in imglist:
#print(img)
try:
urllib.request.urlretrieve(img,'picture/%d.png'%flag)
print('第%d张图片下载完成'%flag)
except:
print('第%d张图片下载异常,请稍后再试'%flag)
flag += 1
将html打印到TXT的代码可注释掉,只是我个人习惯在nodepad++中分析html,方便查找正则规律
爬取TXT的框架类似,只是如果需要爬取一整部小说的内容,需要注意的点还是挺多的,而且需要进行伪装,和网站的安全系统斗智斗勇。
小说链接:https://www.ddxs.cn/book/195261/.
可从具体每一章节中看到,文字都直接存在html中。
首先需要进入小说的章节列表地址,从列表html获取每一章的地址,然后再从具体章节的html中抓取正文,最后优化格式,输出即可
导入库信息
import os
import requests
import re
import time
import random
def get_htmlcode(url):
try:
urlhtml = requests.get(url)
htmlcode = urlhtml.content
# path = open('Txt/html.txt','wb')
# path.write(htmlcode)
# path.close()
except:
htmlcode = 'error'
return htmlcode
形参为网络url,会返回网页的html。
打印html的代码块被我注释了,调试过程中,可取消注释,辅助分析
经过观察可以发现有 最新章节 和章节目录 两块,结构很相似。直接匹配 <a href="/ 开头和 " title= 结尾 ,会将最新章节里的地址也匹配下来,这一块是存在重复的,我们只需要章节目录下的数据,所以需要对html进行处理。以 章节目录 为分割线,之后所有匹配的地址则是我们需要的。
对元素值‘章节目录’进行查找,返回索引值,然后以索引下标进行切片,只保留‘章节目录’后的数据。再对处理后的html进行正则就可以获取每一章的地址。
def get_chapter_list(htmlcode):
htmldecode = htmlcode.decode()
a = htmldecode.index('章节目录')
htmldecode_final = htmldecode[a:]
reg = r'<a href="(.+?)" title="八荒凤鸣'
reg_msg = re.compile(reg)
chapter_list = reg_msg.findall(htmldecode_final)
return chapter_list
这里得到的还不是完整的地址,缺少了这个网址的前缀’https://www.ddxs.cn’。在后面的代码中注意这个点,加上就好
2.2中已经获取到了所有章节的地址列表,通过2.1的方法再获取任意一个章节的html,发现每个章节地址的html格式规律都是相同的,只要遍历地址列表即可。
这里又分两步,匹配章节名、正文的正则表达式规则是不同的
匹配章节名
// 获取章节名称
def get_subject(htmlcode):
reg = '<h1>(.+?)</h1>'
reg_msg = re.compile(reg)
subject = reg_msg.findall(htmlcode.decode())
return subject
匹配正文
// 获取正文
def get_novel(htmlcode):
reg = 'class="content"><p>(.+?)</p></article>'
reg_msg = re.compile(reg)
novel = reg_msg.findall(htmlcode.decode())
# print(novel)
return novel
这里可以分别打印爬取的数据,验证下正则表达式的逻辑是否正确
在2.3中,爬取的正文是一整行的数据,中间杂糅着很多</p><p>。这些就是段落的规律,我们只需要把</p>替换成换行,<p>替换成缩进,就可以形成很符合咱们观看习惯的排版。
// 调整正文格式
def novel_format(novel):
novel = str(novel).replace('</p>','\n')
novel_Format = novel.replace('<p>',' ')
return novel_Format
最后一步是将抓取的章节名和正文写入txt。因为前面已经把方法都写清楚了,到了这一步就轻松多,但是也要注意代码运行的逻辑性。
再是对txt文件进行读写操作时,要注意下打开方式,采用追加方式打开。
也可以自己对文件进行一些调整,比如在每章的正文后面加入一些分割符,或者是两个换行,诸如此类,使排版更清晰一些。
大部分小伙伴,都会遇到被网站后台识别成恶意访问的困难。
最近也和做后台的同学讨论了下,他们判断恶意访问的准则主要为:单位时间内,相同IP的多次连续访问。
我的解决办法其实很傻瓜式,就是以降低性能为代价,强制加入等待时间。
起先等待时间是可以设置成固定值的,比如1秒。但是随着爬取量的上升,后台也会识别到咱们的诡计。
所以我最终决定采用的等待时间是0.5s~1.5s之间的随机数。按照这个反侦察手段,在一定爬取数量和网站对象内,我还未失手。可能是我爬取的数据都是一些不那么重要的资料,网站也大多为盗版。
import os
import requests
import re
import time
import random
#创建目录
if not os.path.exists('Txt'):
os.mkdir('Txt')
#获取网页html
def get_htmlcode(url):
try:
urlhtml = requests.get(url)
htmlcode = urlhtml.content
# path = open('Txt/html.txt','wb')
# path.write(htmlcode)
# path.close()
except:
htmlcode = 'error'
return htmlcode
#获取章节地址列表(无https://www.ddxs.cn前缀)
def get_chapter_list(htmlcode):
htmldecode = htmlcode.decode()
a = htmldecode.index('章节目录')
htmldecode_final = htmldecode[a:]
reg = r'<a href="(.+?)" title="八荒凤鸣'
reg_msg = re.compile(reg)
chapter_list = reg_msg.findall(htmldecode_final)
return chapter_list
#获取章节名称
def get_subject(htmlcode):
reg = '<h1>(.+?)</h1>'
reg_msg = re.compile(reg)
subject = reg_msg.findall(htmlcode.decode())
return subject
#获取正文
def get_novel(htmlcode):
reg = 'class="content"><p>(.+?)</p></article>'
reg_msg = re.compile(reg)
novel = reg_msg.findall(htmlcode.decode())
# print(novel)
return novel
#调整小说格式
def novel_format(novel):
novel = str(novel).replace('</p>','\n')
novel_Format = novel.replace('<p>',' ')
return novel_Format
url_list = 'https://www.ddxs.cn/book/195261/'
#获取章节列表的地址
if __name__ =='__main__':
#小说列表网站的html
Htmlcode_url_list = get_htmlcode(url_list)
if Htmlcode_url_list == 'error':
print('~~~~~~~~~~~~~网页出错了,请稍后再试~~~~~~~~~~~~~')
else:
#从源码中匹配出所有章节的地址
Chapter_list = get_chapter_list(Htmlcode_url_list)
flag = 1
path = open('Txt/八荒凤鸣.txt', 'a')
path.write('~~~~~~八荒凤鸣~~~~~~')
path.write('\n\n\n\n')
#循环处理每个章节地址
for a in Chapter_list:
#逐一处理章节地址,加上前缀
url_chapter = 'https://www.ddxs.cn'+a
try:
# 获取具体章节的html
Htmlcode = get_htmlcode(url_chapter)
# 从章节的html中得到章节名
Subject = get_subject(Htmlcode)
# 从html中得到小说具体内容并优化格式
Novel = get_novel(Htmlcode)
Novel_Format = novel_format(Novel)
# 输入到最终TXT中
path.write(str(Subject))
path.write(str(Novel_Format))
path.write('\n\n')
#加一个提示信息
print('小说八荒凤鸣第%d章节输出完成'%flag)
flag += 1
#随机休息0.5到1.5秒,防止被网站后台封禁
time.sleep(round(random.uniform(0.5,1.5),2))
except:
print('第%d章输出失败,网络错误,请稍后再试'%flag)
path.close()
print('小说爬取完成')
我在程序中加了一些网络异常的分支设计,保证整个程序的健壮性,毕竟是盗版网站,服务器不稳定。
可能是因为我是测试出身,比较在乎程序的友善性反馈。
有兴趣的小伙伴,可以试试将顶点小说网首页出现book id的所有小说数据都爬下来。
不管是爬取png,还是爬取txt,原则上都是换汤不换药。爬虫也不是一种很复杂的知识。掌握精要后,只要是浏览器可以查看的数据,爬虫都可以弄下来。