过去三天学习了python实现网络爬虫的基本方法
trial1:
功能:trial1实现了获取txt文件中的一个网页,然后用预设的Chrome浏览器的header访问这个网页,
识别网页的编码方式,并将网页的源码从二进制解码为网站编码的形式,并将这个网站源代码输出到一个独特的txt文件中
代码与注释如下:
import urllib.request#python内置的url相关库
import chardet#chardet.detect()能够判断网页的编码方式用以解码
import time#用于获取time(),time()是一个与时间一一对应的数值,故具有取文件名需要的独特性
#读取同一个目录下website.txt中第一行的数据作为网页(需自行输入到website.txt中)
f=open('website.txt','r')
url=f.readline()#readline函数:仅在此行中:无输入→全读;输入数字→(仅在此行中)读‘数字’个字符
head={}
head['User-Agent']='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36'#设置一个访问网页时的head
data=None#data是使下方函数正常运行所必须的输入值#data要填入则必须有定义
req=urllib.request.Request(url,data,head)#获取url的信息#data处可直接填入None #用时0.000500s
response=urllib.request.urlopen(req)#获取url的信息#用时0.64646s
html=response.read() #获取二进制格式的网页源码#用时0.070943s
chardetinfo=chardet.detect(html)#获取包含html编码方式的字典 #charset是包含一个‘confidence’值的,代表了一个自信度,所以charset不一定是万全的方法哦。#为提高程序运行效率(chardet.detect耗时1s左右,get_param耗时0.0s【后续位数数值不详】),编码方式可以针对特定的网页进行优化,如百度贴吧网则一定是utf-8编码的,不用另加识别了
if int(chardetinfo['confidence'])<0.9:#confidence在百度贴吧跌到0.47左右,所以此处加一个判断,若confidence过低则实用get_param方法获取charset
charset=response.info().get_param('charset')
else:
charset=chardetinfo['encoding']
decoded=html.decode(charset)#按照charset字典中的信息对二进制格式的网页源码进行解码 #用时极低
f1=open('html_'+str(time.time())+'.txt','w',encoding='utf-8')#用time()函数起名确保了同一时刻取的文件名是独特的 #不规定encoding='utf-8'就输出到txt中可能导致GBK报错 #GBK是汉字国际扩展码,所以这是一个中国人才会遇到的问题呢
f1.write(decoded)#将解码后的网页源码输出到一个新的txt文件中#关于二进制读写,详见图片库'1518889412.1767128'系列
f1.close()
trial2:
trial2实现了在某一个特定贴吧中从首页第一个帖子中的第一个发言开始逐条
寻找目标(源代码中的)字符串出现过的网页(通过改变目标字符串可以做到
寻人、搜索内容等功能),并且在每个贴子中的翻页次数也可以进行设定
注意:由于贴吧是动态变化的,所以获取的信息可能会出现一些误差
注意2:暂时只实现了在源代码中寻找关键词的功能
代码与注释如下:
(详细注释见trial1)
import urllib.request as req
import urllib.parse as parse #parse.quote方法可以进行‘url编码’
from time import time
name=str(input('请输入一个可以访问的贴吧的吧名(如李毅吧则输入李毅)'))
goal=str(input('请输入你想要查找的字符串:'))
t=int(input('是否需要对贴子进行翻页?请输入翻页次数(取值范围[0,...])'))
f=lambda x:t+1 if x>t+1 else x #为了实现翻页次数而设计的函数
head={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36'}
data=None
page=1
count=0
while page==page:#可以通过点击尾页来获取贴吧的总页数
url='https://tieba.baidu.com/f?kw='+parse.quote(name)+'&ie=utf-8&pn='+str((page-1)*50)#parse.quote方法可以进行‘url编码’,经过观察,百度贴吧会对汉字进行url编码 #'*50'是由百度贴吧的url规律总结出来的,用以翻页
print('第'+str(page)+'页')
dest=req.Request(url,data,head)
response=req.urlopen(dest)
html=response.read()
decoded=html.decode('UTF-8')#此处合理省略了编码方式判断来节省时间
position=-1#-1是根据下方的需求决定的
for i in range(decoded.count('title="主题作者')):
position=decoded.find('title="主题作者',position+1)#+1是因为字符串的find函数是从起始值开始且考虑起始值地进行寻找的
stop=decoded.rfind('" title=',0,position)
begin=decoded.rfind('"',0,stop)+1#+1是因为字符串从a取到b是算上a不算上b的,而我的suburl实际上不需要‘"’符号。
suburl='https://tieba.baidu.com'+str(decoded[begin:stop])
subhtml=req.urlopen(req.Request(suburl,data,head)).read()
subdecoded=subhtml.decode('UTF-8','ignore')
#执行↓
if subdecoded.find(goal)!=-1:
print(suburl)
#执行↑
count=count+1
print(count)
#执行后计数:
#翻页部
pagenum_begin=subdecoded.find('回复贴,共<span class="red">')+23#‘23’是一个调试出来的值
pagenum_stop=subdecoded.find('<',pagenum_begin)
pagenum=int(subdecoded[pagenum_begin:pagenum_stop])
for subpage in range(2,f(pagenum)+1):#-2是为了配合函数f
suburl='https://tieba.baidu.com'+str(decoded[begin:stop])+'?pn='+str(subpage)
subhtml=req.urlopen(req.Request(suburl,data,head)).read()
subdecoded=subhtml.decode('UTF-8','ignore')
#执行↓ #这里需要重复的原因是方法决定要想获取子页面的页数需要先打开子页面
if subdecoded.find(goal)!=-1:
print (suburl)
#执行↑
#执行后计数:
count=count+1
print(count)
page=page+1