任务
- 爬取月票榜
- 并把小说保存到本地
效果
代码实现
import requests
import re
from bs4 import BeautifulSoup
import os
import threading
def getHTMLText(url,timeout = 100):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return '错误'
def write_to_file(file,content):
string = ""
# ------------------------------------------- #
# 小说内容处理
soup = BeautifulSoup(content,'lxml')
title = soup.find(class_="title_txtbox").string
print(title)
Paragraphs = soup.select(".content p")
string = string +'\t\t\t\t' + title + '\n\n'
for p in Paragraphs:
string = string + p.string + '\n'
# ------------------------------------------- #
with open(file,'w') as f:
f.write(string)
def download(title,j):
chapter = getHTMLText(j[0]) # 获取章节内容
write_to_file(title+"\\"+j[1]+'.txt',chapter) # 写入文件
def main():
threads = [] # 保存线程
url = "http://www.zongheng.com/"
monthTickInfo = [] # 保存月票榜信息 (排名,小说名,月票数,小说链接)
html = getHTMLText(url) # 爬取月票榜
monthTickList = re.findall(r'<li><span>(\d*)</span><em class=".*?">\d*</em><a href="(.*?)" target="_blank" title="(.*?)" .*?</li>',html)
for i in range(len(monthTickList)):
monthTickInfo.append((i+1,monthTickList[i][2],monthTickList[i][0],monthTickList[i][1])) # 保存信息
for i in monthTickInfo:
print('%-5d %-25s %-10s %40s'%(i[0],i[1],i[2],i[3])) # 打印月票榜
# http://book.zongheng.com/book/1013348.html 替换为 http://book.zongheng.com/showchapter/1013348.html
novel_dir = i[3][:25]+i[3][25:].replace("book","showchapter")
novel_content = getHTMLText(novel_dir) # 爬取书名目录
directory = re.findall(r'<li class=" col-4">[\S\s]*?<a href="(.*?)" target="_blank" title=".*?">(.*?)</a>',novel_content)
# ---------------------------------------------------------- #
# 创建文件夹 名字为书名
if os.path.exists(i[1]):
pass
else:
os.mkdir(i[1])
# ---------------------------------------------------------- #
# 多线程爬取
for j in directory:
T = threading.Thread(target=download,args=(i[1],j))
T.setDaemon(False)
T.start()
threads.append(T)
# ---------------------------------------------------------- #
for T in threads:
T.join()
if __name__ == "__main__":
main()
缺点
- 这么写 ip 容易被禁
解决方法
-
user_agent 伪装
headers = { "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36", }
-
设置访问时间间隔
很多网站的反爬虫机制都设置了访问间隔时间,一个IP如果短时间内超过了指定的次数就会进入“冷却CD”,所以除了轮换IP和user_agent
可以设置访问的时间间间隔长一点,比如没抓取一个页面休眠一个随机时间:import time import random time.sleep(random.randint(1,3))
-
使用代理IP
搜索引擎搜索 “代理” 关键字,就可以看到许多代理服务器网站,网站上会有许多免费代理。但是这些免费代理大多数情况下是不好用的,所以比较靠谱的方法是购买付费代理
但是代理不论是免费的还是付费的,都不能保证都是可用的,因为可能此 IP 被其他人使用来爬取同样的目标站点而被封禁。所以需要提前做筛选,将不可用的代理剔除掉,保留可用代理。