注:此为慕课网Python(不打广告)视频的观看笔记,只做记录之用,并未勘误。
完整的爬虫:
反扒机制,自动登录,代理IP等等
示例爬虫:
简单的数据抓取,简单的数据处理
目的:
不使用爬虫框架完成数据爬取
巩固知识、合理编程、内部原理
示例内容:
内容:
爬取直播网站
确定工作:
确定爬取数据:某个分类下各主播人气的数据
确定实现结果:将人气进行排序
准备:
分析网站结构
寻找包含爬取信息的页面
F12检查网页,定位信息(主播姓名,人气数据)
原理:
对html文件进行文本分析并从中提取信息
使用技术
正则表达式
具体步骤:
模拟HTTP请求,向服务器发送请求,获取到服务器返回的HTML
用正则表达式处理网页文本,过滤出有用数据
找到相关常量标签,作为正则的定位边界
定位标签:
尽量选择具有唯一标识的标识的标签
尽量选择与目标数据相近的标签
尽量选择将所有目标数据都包含的标签(闭合的标签),比如包含姓名+人气的标签
上述即尽量选父标签,不选兄弟标签,为了易于构造正则提取内容
注意:
构造正则不是难点,难点是应对反爬虫的措施
整体书写规范
每行代码不要过长
推荐书写一个入口程序
推荐在入口中平行的调用逻辑代码
每个方法中代码尽量少
注意块注释和行级注释的书写格式
代码结构:
1 |
|
<li class="game-live-item" gid="1">
<a href="http://www.huya.com/yanmie" class="video-info new-clickstat" target="_blank" report='{"eid":"click/position","position":"lol/0/1/5","game_id":"1","ayyuid":"380335691"}'>
<img class="pic" data-original="//screenshot.msstatic.com/yysnapshot/1711a622dc4d670fe32de2018f78a2d030fcde37cfe8?imageview/4/0/w/338/h/190/blur/1" src="//a.msstatic.com/huya/main/assets/img/default/338x190.jpg" onerror="this.onerror=null; this.src='//a.msstatic.com/huya/main/assets/img/default/338x190.jpg';" alt="最强赵信折翼的直播" title="最强赵信折翼的直播">
<div class="item-mask"></div>
<i class="btn-link__hover_i"></i>
<em class="tag tag-blue">蓝光</em> </a>
<a href="http://www.huya.com/yanmie" class="title new-clickstat" report='{"eid":"click/position","position":"lol/0/1/5","game_id":"1","ayyuid":"380335691"}' title="可以用赵信上王者第一的男人" target="_blank">可以用赵信上王者第一的男人</a>
<span class="txt">
<span class="avatar fl">
<img data-original="//huyaimg.msstatic.com/avatar/1081/63/c83bdc0701b64646c86065e273fd05_180_135.jpg" src="//a.msstatic.com/huya/main/assets/img/default/84x84.jpg" onerror="this.onerror=null; this.src='//a.msstatic.com/huya/main/assets/img/default/84x84.jpg';" alt="最强赵信折翼" title="最强赵信折翼">
<i class="nick" title="最强赵信折翼">最强赵信折翼</i>
</span>
<span class="num"><i class="num-icon"></i><i class="js-num">1.5万</i></span>
</span>
</li>
1 |
|
<span class="txt">
<span class="avatar fl">
<img data-original="//huyaimg.msstatic.com/avatar/1081/63/c83bdc0701b64646c86065e273fd05_180_135.jpg" src="//a.msstatic.com/huya/main/assets/img/default/84x84.jpg" onerror="this.onerror=null; this.src='//a.msstatic.com/huya/main/assets/img/default/84x84.jpg';" alt="最强赵信折翼" title="最强赵信折翼">
<i class="nick" title="最强赵信折翼">最强赵信折翼</i>
</span>
<span class="num"><i class="num-icon"></i><i class="js-num">1.5万</i></span>
</span>
1 |
|
from urllib import request
import re
class spider():
url = 'http://www.huya.com/g/lol'
root_pattern = '<span class="txt">([\s\S]*?)\r\n</li>' #父级目录匹配
# 使用概括字符集 [\d] [\w] [\s] [.]
#注意:要加问号,声明是非贪婪的匹配
name_pattern = '<i class="nick" title="([\s\S]*?)">'
num_pattern = '<i class="js-num">([\s\S]*?)</i>'
def __fetch_content(self): #加__的函数:私有方法
tmp = request.urlopen(spider.url)
htmls = tmp.read() #此处的结果是字节码:bytes
# bytes->str
htmls = str(htmls,encoding='utf-8')
a = 1#如果不添加这一句,htmls赋值发生在最后一句
#那么断点停止时会得不到htmls的值,这时要人为多余的添加一条语句并将断点放到这里即可
#print(htmls)不推荐打印,会出现解码问题
return htmls
def __sort(self, pairs):
#def sorted(iterable, cmp=None, key=None, reverse=False)
#注意要指定key值
return sorted(pairs,key=self.__seed,reverse=True)
def __show(self, pairs):
#for循环中需要拿到序号,直接使用range形式的for循环
for rank in range(0, len(pairs)):
print('第',rank,'名:',pairs[rank]['name'],':',pairs[rank]['number'])
def __seed(self, pairs):
tmp = pairs['number'].replace('万','')
if('万' in pairs['number']):
tmp = float(tmp) * 10000
return int(tmp)
def __refine(self, pairs):
f = lambda p: {
'name':p['name'][0].strip(),
'number':p['number'][0]
}
return map(f, pairs)
def __analysis(self, htmls):
root_htm = re.findall(spider.root_pattern,htmls)
pairs = []
for item in root_htm:
name = re.findall(spider.name_pattern,item)
num = re.findall(spider.num_pattern,item)
pair = {'name':name,'number':num}
pairs.append(pair)
return pairs
#设置入口函数,这是一个主方法,里面都是平级函数,推荐这种写法
def go(self):
htmls = self.__fetch_content() #抓取页面内容
pairs = self.__analysis(htmls) #抽取所需数据
pairs = list(self.__refine(pairs)) #数据精炼
pairs = self.__sort(pairs) #数据排序
self.__show(pairs) #数据显示,或后续处理(入库等)
#实例化并调用入口函数
s = spider()
s.go()
注意事项:
如果需要调试,不推荐站桩print,推荐使用断点调试
调试方法:
启动应用程序 F5
单步执行F10
跳到下一个断点 F5
调到函数内部 F11
例如在 html = tmp.read() 处打断点
在当前断点处,悬停鼠标会显示变量值,也可以在vscode左侧的甲壳虫选项中查看变量的值
缺陷:
虽然通过类进行了封装,但是其实最基础的封装
但是,复用性差,抵御需求变化的能力太差,违反开闭原则
进阶:
可以使用更加面向对象的设计来完成功能
借助构造函数__init__来对类进行带参数的实例化:
代码:
class Spider():
'''
This is a class
'''
url = ''
root_pattern = ''
name_pattern = ''
num_pattern = ''
def __init__(self,url,root_pattern,name_pattern,num_pattern):
Spider.url = url
Spider.root_pattern = root_pattern
Spider.name_pattern = name_pattern
Spider.num_pattern = num_pattern
s = Spider(
'http://www.huya.com/g/4',
'<span class="txt">([\s\S]*?)\r\n</li>',
'<i class="nick" title="([\s\S]*?)">',
'<i class="js-num">([\s\S]*?)</i>'
)
s.go()
类封装的意义:
这样封装可以完成一个主播人气排序的爬虫类,参数有四个:
爬取的直播网站;
爬取的名称人气的父元素的正则
爬取名称的正则
爬取人气的正则
展望:
爬虫模块或框架:
BeautifulSoup模块
Scrapy框架(多线程、分布式、较臃肿,看需求谨慎使用)
反反爬虫技术:
频繁爬取会使IP被封,需要使用定时器!切记!!
寻找代理IP库,应对封IP
整个流程的核心:
爬取的原始数据如何处理,精炼
处理的结果如何存储,分析
😒 留下您对该文章的评价 😄