1、小爬爬的诞生
前两天看大神的爬虫文章,自己照着写了一个。经过多次修改,和之前的就大不一样了。
开始只是简单的图片下载,从一个页面中下载所有的图片,代码如下:
import re
from bs4 import BeautifulSoup
import requests
def get_html(url):
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.68 Safari/538.36'}
response=requests.get(url,params=headers)
if response.status_code==200:
print("状态码成功")
if "验证" in response.text:
print("被验证")
return None
else:
return response.text
else:
print("状态码失败"+str(response.status_code))
def parse_html(html,name):
soup=BeautifulSoup(html,'lxml')
results=soup.select(name)
with open('img\\黄图地址.txt','w') as f:
for result in results:
print(result['src'])
f.write(result['src']+'\n')
url='https://www.55df.xyz/pic/5/2020-01-10/25477.html'
html=get_html(url)
if html==None:
print('none')
pass
else:
parse_html(html,name='img')
with open('img\\黄图地址.txt','r')as f:
readlines=f.readlines()
lens=len(readlines)
print(lens)
for i in range(lens):
url=readlines[i].rstrip()
print(url)
filename='img\\'+str(i+1)+'.jpg'
with open(filename,'wb')as f1:
print("正在下载{}".format(i+1))
f1.write(requests.get(url).content)
print("下载完成")
注意:里面的链接地址请自行无视,
如由此引发局部问题请自行解决~ ┗( ▔, ▔ )┛
2、小爬爬的兄弟个子更高吗?
不满足于光爬图片,转眼看到兄弟手机上的“笔趣阁”,露出了迷人的微笑。

兄弟:你奏凯~我不是这种人!
哈哈,在兄弟略显失落的眼神中(为啥是失落?)我开始了给小爬爬生个弟弟的行动(纳尼?生?)|ू・ω・` )
import re
from bs4 import BeautifulSoup
import requests,time
from urllib import parse
#获得页面文件
def get_html(url):
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.68 Safari/538.36'}
response=requests.get(url,params=headers)
response.encoding = "utf-8"
if response.status_code==200:
print("状态码成功")
return response.text
else:
print("状态码失败"+str(response.status_code))
#将获得的章节文件链接保存下来,为了调试和审查,先保存下来再说
def parse_html(html,name):
global url
#树化页面文件
soup=BeautifulSoup(html,'lxml')
#找到章节列表
results=soup.select(name)
#这个是为了后面对链接的修改,将相对路径变成绝对路径
page_url = url
#创建链接的列表
rurls = list()
with open('book地址.txt','w') as f:
for result in results:
#获得章节名称,当时为了核对获得的链接才写的,现在感觉也没啥用
rname =result.text
#获得章节列表,并把相对路径换成绝对路径。使用parse需要先引入urllib
rurls.append(parse.urljoin(page_url,result['href']))
#print([rname,parse.urljoin(page_url,result['href'])])
#将章节链接写入文件里,其实这个文件没啥用,也是调试和审查的时候用的
f.write('"'+rname+'":"'+parse.urljoin(page_url,result['href'])+'"\n')
#返回章节链接列表
return rurls
#获得章节的内容 已废弃,没有删除
def get_content(url):
#引用全局变量:书名
global bookname
#获得章节页面文件
conhtml = get_html(url)
#实例化这个页面
soup=BeautifulSoup(conhtml,'lxml')
获得章节名称
title = soup.select('.bookname h1')[0].text
#创建待写入文件,以章节名为文件名,放在book文件夹里
with open('book\\'+title+'.txt','w',encoding="utf-8") as f:
#写入章节标题
f.write(title+'\n')
#获得章节内容
contents = soup.select('div #content')
#写入章节内容
for content in contents:
f.write(content.text+'\n')
#新写的获取章节内容的函数
def get_book(url):
global bookname
wl = True
wln = 0
#读取时总是出现错误中断,写了这个防止中断
while wl == True:
try:
conhtml = get_html(url)
wl = False
except:
print('erro:',wln)
if wln >10:
wl=False
wln += 1
soup=BeautifulSoup(conhtml,'lxml')
title = soup.select('.bookname h1')[0].text
print(title)
#以书名为文件名,创建一个可追加的文件,每次向后写入各章节内容
with open('book\\'+bookname+'.txt','a',encoding="utf-8") as f:
f.write(title+'\n')
contents = soup.select('div #content')
for content in contents:
#content.p.clear()
#wcon = content.text
#wcon = wcon.replace('<br>','<p>')
#print(wcon)
#content.text.replace(' ','\r\n')
f.write(content.text+'\n')
#获得书的名字
def get_bookname(url):
html = get_html(url)
soup=BeautifulSoup(html,'lxml')
names = soup.select('#info h1')
return names[0].text
#废弃,没有删除
def get_url(url,n,m):
urls = list()
if n == 0:
urls.append(url)
for i in range(n,m):
iurl = url+'index_{}.html'.format(i+2)
urls.append(iurl)
return urls
# 就是因为,八王子在十岁的时候,便开启“神武印记”,现在已经是黄极境后期的年轻武者。
url='https://www.xsbiquge.com/75_75151/'
'''
indexs = get_url('https://www.55df.xyz/text/2/',6,10)
print(indexs)
unumber = 0
for url in indexs:
html=get_html(url)
if html == None:
continue
urls = parse_html(html,'.channel ul li a')
for url in urls:
unumber += 1
print(unumber)
get_content(url)
'''
'''
#html = get_html(url)
#results=parse_html(html,'#list a')
conhtml = get_html('http://www.xbiquge.la/7/7552/3449774.html')
soup=BeautifulSoup(conhtml,'lxml')
contents = soup.select('div #content')
#title.clear()
for content in contents:
content.p.clear()
content.text.replace('<br>','\n')
print(content.text)
'''
#get_content('http://www.xbiquge.la/7/7552/3449774.html')
bookname = get_bookname(url)
html = get_html(url)
urls=parse_html(html,'#list a')
for url in urls:
get_book(url)
看吧看吧,这个代码把书全部下载到一个文件里,结果运行时间好长啊。ヾ(=・ω・=)o网速不给力,下载速度也没法很快。一个3000章以上的小说,要下几个小时…………

3、小爬爬瘦身计划
好吧,坐着等着无聊,又给小爬爬找了个兄弟,功能一样,只是换了个写法(✪ω✪)
import requests
import os
from lxml import html
from urllib import parse
url = 'https://www.xsbiquge.com/99_99638/'
#获得页面文件
def get_html(url):
page = requests.get(url).content.decode('utf-8')
strhtml = html.fromstring(page)
return strhtml
#获得章节链接列表,顺便获得书名
def get_booklist(strhtml):
bookname = strhtml.xpath('//*[@id="info"]/h1/text()')[0]
listurls = [parse.urljoin(url,i) for i in strhtml.xpath('//*[@id="list"]/dl/dd/a/@href')]
return bookname,listurls
#将将各章节内容保存到一个文件中,文件名为书名
def get_bookcontent(conurl,bookname):
nhtml = get_html(conurl)
nname = nhtml.xpath('//*[@class="bookname"]/h1/text()')[0]
ncont = nhtml.xpath('//*[@id="content"]/text()')
if not os.path.exists('book'):
os.makedirs('book')
with open('book\\{}.txt'.format(bookname),'a',encoding="utf-8") as b:
b.write(nname+'\n')
for c in ncont:
c = c.replace('<!--go-->','')
c = c.replace('<!--over-->','')
b.write(c+'\n')
return nname
strhtml = get_html(url)
bookname,listurls = get_booklist(strhtml)
for conurl in listurls:
nname = get_bookcontent(conurl,bookname)
print(nname+':OK')
是不是比之前的简洁一些,可是Lxml用起来很别扭,无法实例化一个页面文件,只能进行字符串的查找,虽然有xpath,但有些页面获得xpath不是很准确。最重要的是,我不喜欢正则!我不喜欢正则!我不喜欢正则!重要的事情说三遍!
(其实就是不会ψ(*`ー´)ψ)
4、小爬爬的分身术
今天用了一天的时间,看多线程的东西,多谢几位大神,给了我灵感和启发。所以让小爬爬可以变身了!究极进化?

import threading
import requests,os,time
from lxml import html
from urllib import parse
#创建Lock()给数组加锁
gLock = threading.Lock()
#公用数组,记录章节下载链接
book_link_lst = []
#公用字典保存book信息
#key:'book_name','index_link','book_path','book_files','thread_isover'
book_info = dict()
#获取html文件
def get_html(url):
page = requests.get(url).content.decode('utf-8')
strhtml = html.fromstring(page)
return strhtml
#获取章节链接返回数组[[index,连接],]
def get_booklist(strhtml):
rlst = list()
#书名写入公用字典
book_info['book_name'] = strhtml.xpath('//*[@id="info"]/h1/text()')[0]
listurls = [parse.urljoin(book_info['index_link'],i) for i in strhtml.xpath('//*[@id="list"]/dl/dd/a/@href')]
return list(zip(range(len(listurls)),listurls))
#生产函数,获取章节链接,放入公用数组
def crate_link(url):
#链接写入公用字典
book_info['index_link'] = url
#初始化结束链接数
book_info['thread_isover'] = 0
#获得索引页页面文件
page = get_html(url)
#获得章节列表,返回的项里包含链接在列表中的顺序index,为以后的排序做准备
book_links = get_booklist(page)
for b in book_links:
#章节列表追加入公用列表
book_link_lst.append(b)
#文件合并
def merge_file():
#获得文件路径
tmpfiledir = book_info['book_path']
#获得文件列表 路径+文件名
tmpnameList = [tmpfiledir+'/'+i for i in os.listdir(tmpfiledir)]
#文件列表写入公用字典
book_info['book_files'] = tmpnameList
#文件排序,文件名前面已经带序号,所以排序不会乱
tmpnameList.sort()
#获得文件名
tmpbookname = book_info['book_name']
#创建合并文件
tmpbookfile = open('book/{}.txt'.format(tmpbookname),'a',encoding = 'utf-8')
#打开文件列表,并读取文件到新文件
for i in tmpnameList:
x = open(i,'r',encoding = 'utf-8')
tmpbookfile.write(x.read())
x.close()
tmpbookfile.close()
#创建多线程
class Down_books(threading.Thread):
#下载章节内容并保存在文件夹里
def run(self):
doit = True
while doit:
#加锁
gLock.acquire()
if len(book_link_lst) == 0:
gLock.release()
continue
else:
#获得链接字符串和编号 (index,url)
tmpindex,tmpurl = book_link_lst.pop()
#解锁
gLock.release()
#获得章节页面
nhtml = get_html(tmpurl)
#获得章节名称
nname = nhtml.xpath('//*[@class="bookname"]/h1/text()')[0]
#获得章节内容
ncont = nhtml.xpath('//*[@id="content"]/text()')
#生成保存目录
book_info['book_path'] = 'books\\{}'.format(book_info['book_name'])
#查询目录是否存在,否则创建书名的目录
if not os.path.exists(book_info['book_path']):
os.makedirs(book_info['book_path'])
#生成文件名,前面加上章节的index,0不够就补够,目的是为了将各章节文件排序,然后合并。不排序就乱了
tmpfilename = '0'*(5-len(str(tmpindex)))+str(tmpindex)+nname
#保存章节内容到文件
with open('books\\{}\\{}.txt'.format(book_info['book_name'],tmpfilename),'w',encoding="utf-8") as b:
b.write(nname+'\n')
for c in ncont:
c = c.replace('<!--go-->','')
c = c.replace('<!--over-->','')
b.write(c+'\n')
print('下载完成:',nname)
#如果待下载链接列表空了,就结束这个循环,完结这个线程
if len(book_link_lst) == 0:
book_info['thread_isover'] += 1
print('线程结束')
#结束循环
doit = False
#启动线程前的准备工作
crate_link('https://www.xsbiquge.com/70_70685/')
#启动线程 5个
for x in range(5):
Down_books().start()
#循环查询待下载列表是否为空,如为空则开始合并文章
Down_doing = True
while Down_doing:
if book_info['thread_isover'] == 5:
merge_file()
Down_doing = False
isdel = input('文件已合并,是否删除各章节文件?y/n:')
if isdel == 'y':
for i in book_info['book_files']:
os.remove(i)
print('文件删除完毕')
print()
else:
time.sleep(10)
一个简单的多线程下载,为啥要用分章节下载后再合并呢?因为多线程无法控制章节下载完成的先后顺序,如果下载后放入一个文件里,那先后顺序不同就全乱套了。
目前我的小爬爬就只是进化到这里,之后还要再继续学习才行。
多看看大神们的巨著,多做些练习~~~
一起加油学习吧!!!

今天努力的你,头发又掉了多少?
本文记录了作者从零开始学习爬虫的过程,从简单的图片下载,到尝试爬取小说全文,再到优化代码实现小爬爬的瘦身,最后运用多线程让爬虫实现并行下载。作者强调了在学习过程中遇到的问题和解决方案,以及对正则表达式的偏好。这是一个关于Python爬虫学习和进阶的故事。

被折叠的 条评论
为什么被折叠?



