爬虫即按照一定规则,自动的抓取万维网信息的程序或脚本。
URL
爬虫是根据网页的地址来寻找网页的,也就是URL(统一资源定位符)
其一般格式为:
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
# protocol:就是指协议,如百度使用 https协议;
# hostname[:port]:指主机名(还有端口号为可选参数),一般网站默认端口号为80
# 如百度的主机名就是 www.baidu.com,这个就是服务器的地址;
# path:主机资源的具体地址,如目录和文件名等。
requsets库和简单方法
request库是一个非常强大的库,官方中文教程地址:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html
其中的方法和说明:
方法 | 说明 |
---|---|
requests.request() | 构造一个请求,支撑一下各方法的基础方法 |
requests.get() | 获取HTML网页的主要方法,对应于HTTP的GET |
requests.head() | 获取HTML网页头信息的方法,对应于HTTP的HEAD |
requests.post() | 向HTML网页提交POST请求的方法,对应于HTTP的POST |
requests.put() | 向HTML网页提交PUT请求的方法,对应于HTTP的PUT |
requests.patch() | 向HTML网页提交局部修改请求,对应于HTTP的PATCH |
requests.delete() | 向HTML网页提交删除请求,对应于HTTP的DELETE |
小说下载
介绍:笔趣看是盗版小说网站,可免费在线阅读,但不支持小说打包下载
目标:爬取笔趣小说网站的小说,打包下载下来
笔趣看:http://www.biqukan.com/
以小说《斗罗大陆》为例:首先打开第一章:
第一章的URL:http://www.biqukan.com/3_3026/1343657.html
用前面提到的requests库获取该页面的HTML信息:
if __name__ = "__main__":
target = 'http://www.biqukan.com/3_3026/1343657.html'
req = requests.get(url=target)
print(req.text)
这样就获取到了页面所有的HTML信息,但其中很多内容我们并不需要,多了很多的div等的HTML标签,这些都是我们不需要的无用信息,我们只需要将其中的正文内容提取出来即可。
所以在获取到了HTML信息后,要将其进行解析,提取所需要的信息。
提取的方法很多,这里用最简单的BeautifulSoup进行解析;
Chrome浏览器在页面内点击右键,选择检查,即可查看页面的HTML内容。
仔细看其中的内容,会发现正文所有的内容都在一个名为:
观察其他标签,发现class属性为showtxt的div标签只有这一个,于是,利用BeautifulSoup提取其中的内容,代码如下:
from bs4 import BeautifulSoup
import requests
if __name__ = "__main__":
target = 'http://www.biqukan.com/3_3026/1343657.html'
req = requests.get(url=target)
html = req.text
bf = BeautifluSoup(html,"lxml")
texts = bf.find_all("div",class_ = "showtxt")
print(texts)
解析HTML之前,需要创建一个BeautifulSoup对象,BeautifulSoup函数内的参数就是此前已经获取到的html信息。然后使用find_all方法,第一个参数是获取的标签名,第二个参数class _ 是标签的属性。
但我们还是发现多了其他的一些标签不是我们想要的。find_all匹配的返回的结果是一个列表。所以可以提取匹配结果后,使用text属性,提取文本内容,滤除br标签。随后使用replace方法,剔除其中的空格,替换为回车进行分段。 \xa0在html中是用来表示空格的。replace(‘\xa0’*8,’\n\n’)就是去掉下图的八个空格符号,并用回车代替:
这样,第一章就已经下载完成了。
但如果想要下载整本书呢?同样,回到小说的目录页面下,点检查,查看页面的html信息;
可以看到,文章的章节名都存放在class属性为listmain的标签内:
其中,< div >为父标签,< dl >为子标签,< dd >为孙标签;分别对应开头结尾为< div > < /div >类似形式。
而在< dd > 和< /dd >中找到的目录内容可以看到,存储形式为:
< a href=”/3_3026/1344261.html” >第二百三十六章 大结局,最后一个条件(全书完)
从中可以看到,不同章节的【href】属性不同,而且该属性正好对应着每一章节的URL后半部分,如此一来,我们便可以根据href属性来获取每个章节的连接和名称。
所以,再使用find_all的方法,来首先将目录提取出来:
import requests
from bs4 import BeautifulSoup
if __name__ == "__main__":
target = "http://www.biqukan.com/3_3026/" #小说的页面网址
req = requests.get(url=target)
html = req.text
div_bf = BeautifulSoup(html,"lxml")
div = div_bf.find_all('div',class_ = 'listmain')
print(div[0])
得到所有的目录内容:
然后要提取其中的章节链接和章节名:
from bs4 import BeautifulSoup
if __name__ == "__main__":
server = "http://www.biqukan.com"
target = "http://www.biqukan.com/3_3026/" #小说的页面网址
req = requests.get(url=target)
html = req.text
div_bf = BeautifulSoup(html,"lxml")
div = div_bf.find_all('div',class_ = 'listmain')
a_bf = BeautifulSoup(str(div))
a = a_bf.find_all('a')
for each in a:
print(each.string,server + each.get('href'))
如此便得到了我们想要得到的章节名+链接
于是,将上面的步骤整合一下:
- 首先要定义一个类,其中有属性章节名、章节链接、章节数,网站URL,小说URL等信息
- 然后定义方法:
- 获取下载链接:先通过爬取目标小说的页面获取所有章节名和连接,存入定义的空数组内
- 获取章节内容:得到连接后,返回其中正文内容
- 将文章内容写入文件:以写的方式打开文件,”a”追加模式,tf-8编码格式;先写入章节名,回车;在写入正文;最后再空两行和下一章节隔开。
程序源码
# Author WdZh
# -*- coding:UTF-8 -*-
from bs4 import BeautifulSoup
import requests
import sys
class Download(object):
'''
类说明:下载笔趣看网站小说《斗罗大陆》
'''
def __init__(self):
self.server = 'http://www.biqukan.com'
self.target = "http://www.biqukan.com/3_3026/"
self.names = [] #存放章节名
self.urls = [] #存放章节连接
self.nums = 0 #章节数
def get_download_url(self):
'''
函数说明:获取下载链接
:return:
'''
req = requests.get(url=self.target)
html = req.text
div_bf = BeautifulSoup(html,"lxml")
div = div_bf.find_all("div",class_ = "listmain")
a_bf = BeautifulSoup(str(div[0]),'lxml')
a = a_bf.find_all("a")
self.nums = len(a[15:]) #剔除开头的最新章节以及外传,从第15行开始
for each in a[15:]:
self.names.append(each.string)
self.urls.append(self.server + each.get("href"))
def get_contents(self,target):
'''
获取章节内容
:param self:
:param target:
:return:
'''
req = requests.get(url = target)
html = req.text
bf = BeautifulSoup(html,"lxml")
texts = bf.find_all('div',class_ = 'showtxt')
texts = texts[0].text.replace("\xa0"*8,"\n\n")
return texts
def writer(self,name,path,text):
'''
将爬取的文章内容写入文件
:param self:
:param name:章节名
:param path:当前路径下,小说保存名称(string)
:param text:章节内容
:return:None
'''
writer_flag = True
with open(path,"a",encoding="utf-8") as f:
f.write(name + '\n')
f.write(text)
f.write('\n\n')
if __name__ == "__main__":
dl = Download()
dl.get_download_url()
print("《斗罗大陆》开始下载:")
for i in range(dl.nums):
dl.writer(dl.names[i],'斗罗大陆.txt',dl.get_contents(dl.urls[i]))
sys.stdout.write("已下载:%.3f%%" % float(i/dl.nums) + '\r')
sys.stdout.flush() # %.3f是指小数点后三位
print("《斗罗大陆》下载完成")