Python起点爬虫

时间:2022-07-23
本文章向大家介绍Python起点爬虫,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

类似前言一样得东西

起点小说的爬虫是我写的第一个程序,但是之前的那个写的是真的太垃圾了,爬下来的东西也不是人能看的,所以就趁着自己有时间,重新写了一个,稍微优化了一下下

====分割线====

按流程来吧,首先先导入所需要的库

from urllib.request import urlopen
from bs4 import BeautifulSoup
import time

打开起点中文网中,免费专区

https://www.qidian.com/free

上一个版本中,我写的爬虫是需要用户来给定URL的,但是想了想这一点都不爬虫,于是我就把爬虫获取书籍url的部分写上去了

首先先看看小说名和URL在哪个元素下

发现在div下的h4下的a元素,是链接地址和小说名。

Python中利用Bs4查找的方法有很多种,怎么用看个人喜好,这里给个url供参考就好了

https://www.cnblogs.com/gl1573/p/9480022.html

如果不是特别奇怪的那种,我一般都是一级一级的方式来查找的

.....
url="https://www.qidian.com/free" #免费区的url
html=urlopen(url)
bsObj=BeautifulSoup(html,"html5lib") #分析源码
fname=bsObj.select('div > h4 > a') #查找div下的h4下的a

因为查找出来的结果不只有一个,所以得通过循环来将内容输出出来

.....
fname=bsObj.select('div > h4 > a') #查找div下的h4下的a
for i in fname:
    a=i.get_text()
    b=i.get('href')
    print(a+b)

有了名字和url后,当然不能只是print这么简单,我这里采用的方法是,添加进列表里

先在上面创建两个列表,一个是存名字的,一个是存url的

book_name=[]
book_url=[]

接着,用进for循环中.

.....
#改动后
book_name=[]
book_url=[]
num=1
for i in fname:
    if num==7:
        break
    a=i.get_text()
    print("["+str(num)+"]: "+a)
    b=i.get('href')
    book_name.append(a)
    book_url.append(b)
    num+=1

上面的num,是用来给用户选择所需要爬取的书籍,用户输入ID对应ID就可以选择了,效果图是这样的

有了书的URL后,打开来就到这个页面了,因为这里还不是小说正文部分,所以还需要进一步的获取URL,还是老套路,找到 免费试读所在的部分

发现是在id叫做 redBtn的元素下,安排

def get_url(url):
    html=urlopen("https:"+url)
    bsObj=BeautifulSoup(html,"html5lib")
    neir=bsObj.select('#readBtn') #井号可代替id,#readBtn就等于id=readBtn
    nurl=neir[0].get('href') #因为是列表的属性,所以得[]
    return nurl

这个时候,打开来才是小说的正文部分,这里首先考虑三个点

  • 保存的文件名
  • 章节
  • 正文

第一得先知道我爬取的小说名叫什么,这个是后面作为保存的文件名,你可以从这里获取

当然也可以直接从前面获取的 book_name保存来用

whichbook=int(input("请选择书籍ID:")
bkname=book_name[whichbook-1]

因为给人看的话,从1开始会比较好,但是python中的索引是从0开始,所以在选择的时候,得减去1,这样才是正确的

第一点解决了,现在来看看第二点,小说章节名,章节名可以说比文件名重要,毕竟如果没了章节名,看到第几章都不知道,没有一个分隔的地方了

我这里的写法比较懒,因为在开发者工具中,直接就看到了 title是章节名,就直接拿来用了(也算标明出处?)

html=urlopen(url) #获取源码
bsObj=BeautifulSoup(html,"html5lib") #分析
bt=bsObj.find('title') #获取章节名
print(bt.get_text()) #获取文本内容

第二点倒是很简单就按排上了,下面就是第三点了,小说正文

我第一次写的时候的效果是这样的

这排版。。老实说。就是屎。。

于是乎,稍微改动了一下,原本是一整个正文当作一个部分来处理,现在拆开来,每一句后面都加一个 n,改动后得效果就是这样了

写是这样写的

先找到 divclass="read-content">

bsObj=BeautifulSoup(html,"html5lib")
chapter=bsObj.find("div",{"class","read-content"})

接着在写一个利用 find_all()的,将里面的p全部获取一遍,然后每一个,后面都加上一个 n就好了

...
chapter=chapter.find_all("p")
for i in chapter:
    print(i.get_text().replace(" ","")+"n")

"replace是用来删除空格的,感觉没啥用"

文件名,章节名,正文都有了,接下来就是怎么把“下一章”的内容给爬取出来的问题了

开发者工具中查看位置

然后.find()查找

while True:
    html=urlopen(url)
    bsObj=BeautifulSoup(html,"html5lib")
    bsoup=bsObj.find("",{"id":"j_chapterNext"})
    url="http:"+bsoup.get('href')

这样就能一直下一页,直到结束了,为什么url前面要加一个 http:呢,因为他获取下来的 href,是没有这玩意的,如果拿这个直接去请求的话,会提示url不存在,所以得拼接一下,除此之外,这里还有个问题,怎么判断小说结束了,毕竟我是无限循环

如果你是最后一章的话,那么就不存在正文和标题这两个玩意了,那么在获取的时候,便是空内容,这时,程序会报错,所以只需要写多一个异常处理就好了,写入文件这部分,整合一下就变成了

url="xxx"
while True:
html=urlopen(url)
try:
    bsObj=BeautifulSoup(html,"html5lib")
    bt=bsObj.find('title') #查找章节名字
    chapter=bsObj.find("div",{"class","read-content"}) #查找小说
    chapter=chapter.find_all("p")
    fo=open(bkname+".txt","a",encoding='UTF-8') #保存txt文件,并将名字设置为小说名
    fo.write("n"+bt.get_text()+"n") #内容写入
    for i in chapter:
    fo.write("n"+i.get_text().replace(" ","")) #内容写入
    fo.close() #关闭文件
    bsoup=bsObj.find("",{"id":"j_chapterNext"}) #获取下一章的url
    url="http:"+bsoup.get('href')+".html" #拼接语句
except:
    print ("抓取完毕.....")
    time.sleep(2)
    break

如果报错了,就说明是到尾章了,认为抓取完毕,休息两秒,退出循环

到这里整个程序就全部都写完了

源码我放在了 github,有需要的自行下载就好了

https://github.com/Ernket/qidianpachong/tree/master