十三、原生爬虫实战

一、简单实例

1、需求:爬取熊猫直播某类主播人气排行

2、了解网站结构

分类——英雄联盟——"观看人数"

3、找到有用的信息

二、整理爬虫常规思路

1、使用工具chrome——F12——element——箭头——定位目标元素

目标元素:主播名字,人气(观看人数)

 

2、方法:使用正则表达式提取有用的信息

主播名字,人气(观看人数)

总结

  • 爬虫前奏

1)明确目的

2)找到数据对应的网页

3)分析网页的结构找到数据所在的标签位置

  • 步骤

1)模拟HTTP请求,向服务器发送这个请求,获取到服务器返回给我们的HTML

2)用正则表达式提取我们要的数据(名字,人气)

二、断点调试

我们以如下的一种常见错误,来演示如何通过PyCharm断点追踪的方式发现程序中的错误:

def foo(bar=[]):
    bar.append('bar')
    return bar
>>>foo()
['bar']
>>>foo()
['bar', 'bar']
>>>foo()
['bar', 'bar', 'bar']

这里存在一个常见的错误就是误以为:函数在每次不提供可选形参时将参数设置为默认值,也就是本例中的[],一个空的list。

这里我们便可以通断点调试的方式进行追踪,在每次函数调用(不显示传递形参)时,观察形参值的变化。
如图所示为:


这里写图片描述

下图是以这段为例,来演示如何发现程序中的bug:

这里写图片描述

解决方案:

def foo(bar=None):
    if not bar:
        bar = []
        bar.append('baz')
    return bar
>>>foo()
['baz']
>>>foo()
['baz']

三、HTML结构分析基本原则

1、爬虫分析,最重要的一步,找到标签(即左右边界)

原则:

1)尽量选择有唯一标识性的标签

2)尽量选择离目标信息最近的标签

不同人选择的标签可能不同。

 

四、数据提取层级及原则

1、找到最近的定位标签(肉眼可见)

有关联的信息作为一组,找离这一组最近的定位标签

如:示例中的“主播姓名”和“人数”是有关联的,作为一组

2、判断选择的标签是否是唯一的(需代码验证)

3、尽量选择可闭合的定位标签

 

可闭合,是指可将目标信息包裹起来的定位标签。如:<... />

 

 

4、代码实战

 1 # coding=utf-8
 2 import re
 3 from urllib import request
 4 
 5 url = 'https://www.panda.tv/all'
 6 r = request.urlopen(url)
 7 htmls = r.read()
 8 
 9 print(type(htmls))  # 打印type,结果是bytes类型
10 htmls = str(htmls, encoding='utf-8')  # 将bytes转成utf-8
11 print(htmls)

运行结果

Traceback (most recent call last):
  File "E:/pyClass/thirtheen/spider.py", line 12, in <module>
    print(htmls)
UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position 62321: illegal multibyte sequence

原因是使用的print()是win7系统的编码,但是win7系统的默认编码是GBK,解决方式,增加如下代码

1 import io
2 import sys
3 sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')

优化后代码

# coding=utf-8
import re
from urllib import request
import io
import sys
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')

class Spider():

    url = 'https://www.panda.tv/all'

    def __fetch_content(self):
        r = request.urlopen(Spider.url)
        htmls = r.read()
        htmls = str(htmls, encoding='utf-8')  # 将bytes转成utf-8
        print(htmls)
        return htmls


    def go(self):
        self.__fetch_content()



spider=Spider()
spider.go()

 

五、正则分析HTML

1、获取root_html

正则表达式匹配<div class="video-info">和</div>之间的所有字符,有哪些方式?

匹配所有字符的方式

1)[\s\S]*?

2)[\w\W]*?

* 表示任意次

?表示贪婪

2、代码实战

 

 1 # coding=utf-8
 2 from urllib import request
 3 import re
 4 import io
 5 import sys
 6 sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')
 7 
 8 #以下代码解决SSL报错
 9 import ssl
10 ssl._create_default_https_context = ssl._create_unverified_context
11 
12 
13 class Spider():
14 
15     #定义类变量
16     url = 'https://www.panda.tv/all'
17     root_html='<div class="video-info">([\s\S]*?)</div>'  #([\s\S]*?)匹配任意字符
18 
19     #获取服务器响应内容
20     def __fetch_content(self):
21 
22         r=request.urlopen(url=Spider.url)
23         htmls = r.read()
24         htmls = str(htmls, encoding='utf-8')  # 将bytes转成utf-8
25         return htmls
26 
27     #分析并获取元素
28     def __analysis(self,htmls):
29         root_html=re.findall(Spider.root_html,htmls)
30         return root_html
31 
32 
33     def go(self):
34         htmls=self.__fetch_content()
35         self.__analysis(htmls)
36 
37 
38 spider=Spider()
39 spider.go()

遇到的问题:

1)乱码

参考python的编码问题整理

2)SSL错误

加入如下代码

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

 

3)类变量的引用

Spider.root_html

六、数据精炼

正则分析获取名字和人数

1、找到名字的左右边界、找到人数的左右边界

2、使用正则匹配,从root_html中获取名字和人数,并拼接成字典格式,列表接收

3、数据精炼——去掉多余的换行和空格(如果有),将value列表转化为str

代码示例:

 1 # coding=utf-8
 2 from urllib import request
 3 import re
 4 import io
 5 import sys
 6 
 7 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030')
 8 
 9 # 以下代码解决SSL报错
10 import ssl
11 
12 ssl._create_default_https_context = ssl._create_unverified_context
13 
14 
15 class Spider():
16     # 定义类变量
17     url = 'https://www.panda.tv/all'
18     root_html = '<div class="video-info">([\s\S]*?)</div>'  # ([\s\S]*?)匹配任意字符
19     name_pattern = '<span class="video-title" title="([\s\S]*?)">'
20     number_pattern = '<span class="video-number">([\s\S]*?)</span>'
21 
22     # 获取服务器响应内容
23     def __fetch_content(self):
24         r = request.urlopen(url=Spider.url)
25         htmls = r.read()
26         htmls = str(htmls, encoding='utf-8')  # 将bytes转成utf-8
27         return htmls
28 
29     # 分析并获取元素
30     def __analysis(self, htmls):
31         anchors = []  # 使用list接收
32         root_html = re.findall(Spider.root_html, htmls)
33         for html in root_html:
34             name = re.findall(Spider.name_pattern, html)
35             number = re.findall(Spider.number_pattern, html)
36             anchor = {'name': name, 'number': number}  # 组合成需要的字典格式
37             anchors.append(anchor)
38 
39         return anchors
40 
41     # 数据精炼——去掉多余的内容,转成需要的格式
42     def __refine(self, anchors):
43         l = lambda anchor: {'name': anchor['name'][0], 'number': anchor['number'][0]}  # 上一步得到的name和number是列表类型,需要转成str
44         return map(l, anchors)
45 
46 
47     def go(self):
48         htmls = self.__fetch_content()
49         anchors = self.__analysis(htmls)
50         anchors=list(self.__refine(anchors))
51         print(anchors)
52 
53 
54 spider = Spider()
55 spider.go()

九、业务处理——排序

 

posted @ 2018-08-03 17:31  小白2510  阅读(512)  评论(0编辑  收藏  举报