今天开始学习爬虫啦,学完爬虫就要开始干大事咯。本次学习主要参考:
Jack-Cui python 爬虫系列
我只记录下关键的学习内容,系统的东西还是要参考博主原文。
1 爬虫的简介
爬虫就是通过网页地址URL获取服务器发送给浏览器的网址HTML信息。
2 简单实例,下载小说
使用requests库进行爬取信息。requests的基础方法
第一节课的实战是小说下载,由于原博主提供的小说已经目前我不能爬,所以我换了一个龙族5,龙族5挺好看的。
2.1 获取全网页信息
首先第一步就是获取整个网页的信息。这用到了requests.get()
if __name__ == '__main__':
target = 'http://m.yunxs.com/longzu5/8897118.html'
req = requests.get(url = target)
print(req.text)
2.2 解析网页信息
提取网页感兴趣的方法有正则表达式、Xpath、Beautiful Soup等。
正文的内容保存在
<div>的标准模式为<div id=" ",class="",style=""
id和class是div的标签属性,一个属性对应一个属性值,用于区分不同的div标签。在本例子中,div的属性值为:id=‘chaptercontent’ class=‘Readarea ReadAjax_content’。通过下面的代码可以获得div标签内的内容。
from bs4 import BeautifulSoup as BS
html = req.text
bs = BS(html)
#text = bs.find_all('div',class_='Readarea ReadAjax_content')
text = bs.find_all('div',id='chaptercontent') #这里需要注意id没有'_'
#text = bs.find_all('div',id='chaptercontent',class_='Readarea ReadAjax_content')
print(text)
在上述代码执行后,还会出现<br>
、<div>
、空格等我们不需要的内容。find_all返回结果是一个列表,使用text属性可以获得文本内容,滤除标签。再使用replace方法,剔除空格,替换回车进行分段。 在html中是用来表示空格的。replace(‘\xa0’*8,’\n\n’)就是去掉下图的八个空格符号,并用回车代替。
fin_text = text[0].text.replace('\xa0*4', '\n\n')
2.3 下载整本小说
要下载整本小说,就要获取每个章节的链接。我们在小说目录页进行检查。我们发现章节链接放在了class属性为"book_last"的<div>
标签下,而具体链接又在<dd>
标签下。
<dd>
标签内又有<a>
标签,<a>
标签用于定义超链接,href属性指示链接的目标。
<a href ="/longzu5/619908.html" >5、《龙族5》预告<a/>
因此我们通过获取<a>
的href值就可以获得各个章节的链接和名称。我们先匹配class属性的<div>
标签,再匹配<a>
标签。
ps:后来发现直接取标签a就可以了,不用在父节点下检索
###匹配标签a
from bs4 import BeautifulSoup as BS
import requests
if __name__ == '__main__':
server = 'http://m.yunxs.com'
target = 'http://m.yunxs.com/longzu5/'
req = requests.get(url = target)
html = req.text
bs_html = BS(html)
div = bs_html.find_all('div',class_ = 'book_last')
a_bf = BS(str(div))
a = a_bf.find_all('a')
links = []
chapters = []
for each in a:
#print(each.get('href'))
links.append(server+ each.get('href'))
chapters.append(each.string+ " " + server+ each.get('href'))
#print(links)
texts=[]
for target in links:
req = requests.get(url = target)
html = req.text
bs_html = BS(html)
div = bs_html.find_all('div',id='chaptercontent')
#print(div)
fin_text = div[0].text.replace('\xa0'*4, '\n')
# print(fin_text)
texts.append(fin_text)
print(texts)
与原文例子不同,龙族中的目录分页存在不同网页中,因此需要跳转到不同网页获取所有的目录,本文写了一个获取所有目录链接的代码,之后用set()获得不一样的目录。当然,由于每一页重复的章节相同,可以直接从某一个链接开始添加,这样就不会得到乱序的目录。
由于一章中获取下一页的方法相似,因此不再浪费时间做探讨。
#有下一页的存在把所有链接读出来
from bs4 import BeautifulSoup as BS
import requests
if __name__ == '__main__':
server = 'http://m.yunxs.com'
links = []
contain_pages = []
next_page = True
target = 'http://m.yunxs.com/longzu5/'
while next_page == True:
req = requests.get(url = target)
html = req.text
bs_html = BS(html)
div_booklist = bs_html.find_all('div',class_ = 'book_last')
a_bf = BS(str(div_booklist))
a = a_bf.find_all('a')
for each in a:
links.append(server+ each.get('href'))
# next_page = False
#print(links)
div_nextpage = bs_html.find_all('div',class_ = 'listpage')
a_bf = BS(str(div_nextpage))
a = a_bf.find_all('a')
for each in a:
contain_pages.append(each.get('href'))
print(contain_pages)
print(contain_pages[1])
if contain_pages[1] == None:
next_page = False
print("bubu")
break
else:
print("haha")
target = server+str(contain_pages[1])
contain_pages.clear()
print(links)
print(len(links))
links = set(links)
print(links)
print(len(links))
最后使用原博文作者的方法下载整本小说,包括使用了一章下一页的方法。
from bs4 import BeautifulSoup as BS
import requests,sys
class downloader(object):
def __init__(self):
self.server = 'http://m.yunxs.com'
self.target = 'http://m.yunxs.com/longzu5/'
self.names = [] #存放章节名
self.urls = [] #用来存放链接
self.nums = 0 #章节数
def get_download_url(self):
req = requests.get(url = self.target)
html = req.text
div_bf = BS(html)
div = div_bf.find_all('div',class_ = 'book_last')
a_bf = BS(str(div))
a = a_bf.find_all('a')
self.nums = len(a)
for each in a:
self.names.append(each.string)
self.urls.append(self.server+each.get('href'))
def get_contents(self,target):
req = requests.get(url = target)
html = req.text
bf = BS(html)
texts = bf.find_all('div',id='chaptercontent')
fin_text = texts[0].text.replace('\xa0'*4, '\n')
links = []
next_page_link = bf.find_all('a',id="pb_next",class_='Readpage_up')
#print(next_page_link)
for each in next_page_link:
#print(service)
links.append(service + each.get('href'))
#print(links)
if links!=[]:
#print(links[0])
req = requests.get(url = links[0])
html = req.text
bs = BS(html)
text2 = bs.find_all('div',id='chaptercontent')
fin2_text = text2[0].text.replace('\xa0'*4, '\n\n')
#print('haha')
#print(fin2_text)
final_text = fin_text + '\n\n' + fin2_text
return final_text
def writer(self,name,path,text):
write_flag = True
with open(path,'a',encoding='utf-8') as f: #'a'也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
f.write(name+"\n")
f.writelines(text)
f.write('\n\n')
if __name__ == '__main__':
dl = downloader()
dl.get_download_url()
print('龙族开始下载:')
path = 'C:\\Users\\Administrator\\Anaconda3\\Web_Spider\\lesson 1'
for i in range(dl.nums):
dl.writer(dl.names[i], '龙族.txt',dl.get_contents(dl.urls[i]))
sys.stdout.write("已下载:%0.3f%%" % float(i/dl.nums) + '\r') #\r 默认将指针返回到最开始后输出(在原位置再次输出)
sys.stdout.flush()
print('finish')
至此小说下载的实战就结束啦。撒花。