爬虫(03)面向对象写爬虫(函数,类,post有道翻译,requests)2020-12-16

1. 写一个爬帖子的项目

我们先打开百度贴吧输入“海贼王”,然后随便打开两页,复制一下url,研究一下规律。

https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&ie=utf-8&pn=50
https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&ie=utf-8&pn=100

以上是我点开的第二页和第三页的url,经过观察我们可以看到这样的规律

https://tieba.baidu.com/f?    # 基本的url
kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B  # 这个应该是我们输入的关键字的16进制编码
&ie=utf-8  # 这个是译码的
&pn=50  # 这个应该是页码有关的数字
# 我们看到页码的规律是(页数-1)×50

我们可以构建要抓取页的url了,下面是面向过程的代码:

# 百度贴吧项目
'''
https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&ie=utf-8&pn=50
https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&ie=utf-8&pn=100
'''
import urllib.request
import urllib.parse

base_url = 'https://tieba.baidu.com/f?'
start_page = int(input('请输入起始页:'))
end_page = int(input('请输入结束页:'))
key = input('请输入你要搜索的主题:')
kw = {'kw':key}
kw = urllib.parse.urlencode(kw)
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36'}

for i in range(start_page,end_page+1):   # 因为range()函数的特点是左含右不含,所以要加上1才能够输出结束页
    pn = (i-1)*50
    url = base_url+kw+'&ie=utf-8'+'&pn='+str(pn)   # 这里要转换成字符串才能拼接
    req = urllib.request.Request(url,headers=headers)
    res = urllib.request.urlopen(req)
    html = res.read().decode('utf-8')
    with open(r'D:\spiderdocuments\tieba_{}_page_{}.txt'.format(key,i),'w',encoding='utf-8') as f:
        f.write(html)
        print(f'第{i}页已经成功写入!')
print('程序执行完毕')

在我输入相关的信息后,这个执行结果就是在我的相应盘里多出来这么几个文件
在这里插入图片描述

2. 面向对象编程

我们可以将上述代码用面向对象编程的思想来尝试编写

2.1 使用函数对象编程

我大概把面向过程编程的内容分成以下几个步骤:

  • 抓取网页 生成要写入文本的内容
  • 写入文本
  • 主程序 生成抓取网页需要的url
  • 主入口判断语句
    所以我大概可以先写这样一个框架
import urllib.request
import urllib.parse
def readpage(url):
	pass
def writepage(filename,html)
	pass
def main():
	pass
if __name__ == '__main__':
	main()

下面我们把必要的内容移入各自的函数,得到如下结果:

# 面向对象,函数
import urllib.request
import urllib.parse


def readpage(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36'}
    req = urllib.request.Request(url, headers=headers)
    res = urllib.request.urlopen(req)
    html = res.read().decode('utf-8')
    return html


def getpage(filename, html):
    with open(filename, 'w', encoding='utf-8') as f:
        f.write(html)
        print('写入成功')


def main():
    base_url = 'https://tieba.baidu.com/f?'
    key = input('请输入你要搜索的内容:')
    start_page = int(input('请输入起始页:'))
    end_page = int(input('请输入结束页:'))
    kw = {'kw': key}
    kw = urllib.parse.urlencode(kw)
    for i in range(start_page, end_page + 1):
        pn = (i - 1) * 50
        url = base_url + kw + '&ie=utf-8' + str(pn)
        html = readpage(url)
        filename = r'D:\spiderdocuments\爬虫结果第{}页.txt'.format(i)
        getpage(filename, html)


if __name__ == '__main__':
    main()

当输入相关的数据后,执行结果是在我相应的文件夹里出现一些新的文件:
在这里插入图片描述

2.2 使用类对象编程

代码如下,慢慢琢磨:

import urllib.request
import urllib.parse

'''
类属性 实例属性 类方法 实例方法 (静态方法) 实现老师课堂上面的 自己在去优化 创新
'''
class BaiduSpider:
    # 把常用的不变的放到init方法里面
    def __init__(self):
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
        }
        self.base_url = 'https://tieba.baidu.com/f?'

    def readPage(self,url):
        req = urllib.request.Request(url, headers=self.headers)
        res = urllib.request.urlopen(req)
        html = res.read().decode('utf-8')
        return html

    def writePage(self,filename,html):
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(html)
            print('写入成功')

    def main(self):
        name = input('请输入贴吧的名称:')
        begin = int(input('请输入起始页:'))
        end = int(input('请输入终止页:'))
        kw = {'kw': name}
        result = urllib.parse.urlencode(kw)

        for i in range(begin, end + 1):
            pn = (i - 1) * 50
            url = self.base_url + result + '&pn=' + str(pn)
            # 调用函数
            html = self.readPage(url)
            filename = '第' + str(i) + '页.html'
            self.writePage(filename, html)
if __name__ == '__main__':
    spider = BaiduSpider()
    spider.main()

这个和使用函数不同的是:

  • 定义了初始化方法,把headers,base_url放进去。
  • 引用headers和base_url的时候用self.headers和self.base_url
  • 在主函数中调用类中的方法的时候也是用self.readpage(url)和self.getpage(filename,html)
    这些都遵循了类的属性和方法的调用规则,其他的基本没有什么改变。执行的时候页右主入口判断语句,不过后面跟的是实例化类,和用实例调用主函数。

3. post案例:有道翻译项目

下面我们尝试写一个爬取有道翻译的项目,目标是实现输入中文或者英文,翻译成英文或中文并输出。
方法步骤:

  • 请求数据 请求的url地址需要携带数据
  • Request URL:http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
  • Request Method:POST
  • User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/49.0.2623.75 Safari/537.36X-Requested-With:XMLHttpRequest
  • 需要的form data
i:ni'hao
from:AUTO
to:AUTO
smartresult:dict
client:fanyideskweb
salt:16080913521534
sign:77ea47df15df6aab9c8795ae97b3738c
lts:1608091352153
bv:03c7fe57b6c3c6df93436a3d08a92a66
doctype:json
version:2.1
keyfrom:fanyi.web
action:FY_BY_REALTlME
  • 解析数据 得到翻译的结果
    以上是我们的思路。
    在这里插入图片描述
    下面是我们的代码,请仔细看注释:
# 有道翻译
import urllib.request     # 先引用必要的模块
import urllib.parse
content = input('请输入你要查找的内容:')   # 接收所要查询的内容
# 这个数据表格是我们在网页内得到的
data = {
    'i': content,
    'from': 'AUTO',
    'to': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': '16080848522314',
    'sign': '4411bb288b085cd52841d65ddde0d8f8',
    'lts': '1608084852231',
    'bv': '03c7fe57b6c3c6df93436a3d08a92a66',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'
}

'''
TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.
'''
data = urllib.parse.urlencode(data)  # 要把data进行编译一下
data = bytes(data,encoding='utf-8')  # 而且要把data转换成字节类型,并且要编译,不然会报错如上面注释。
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
# http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
# 在这里我们要删掉_o,不然的话会报错:{"errorCode":50},我们暂时这样处理,就不会报错了。以后学了js逆向后再解释。

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36X-Requested-With:XMLHttpRequest'} # 用soft wrap功能可以换行
# 以下代码是请求以及获取数据:
req = urllib.request.Request(url,data=data,headers=headers) # 将url,data,headers都当成参数传入
res = urllib.request.urlopen(req)
html = res.read().decode('utf-8')
print(html)

当我执行以后,在提示中输入:你好。结果如下:

请输入你要查找的内容:你好
                          {"type":"ZH_CN2EN","errorCode":0,"elapsedTime":0,"translateResult":[[{"src":"你好","tgt":"hello"}]]}

我们看到得到的好像是字典,也许你会用字典的知识取出所要的数据。但是,这里注意,其实输出的是字符串,不信我们检查一下:

print(type(html))

结果

请输入你要查找的内容:nihao
<class 'str'>

所以,一定要先转换成字典,这就要用到一个工具——json,功能是把字典类型的字符串转换成字典。

html = res.read().decode('utf-8')
r_dict = json.loads(html) # 把字符串转换成字典
print(type(r_dict))

注意我只写了最后三行代码,前面的省略了,其中要记得先import json不然会提示错误。
执行结果:

请输入你要查找的内容:你好
<class 'dict'>

就是我们熟悉的字典类型了。后面我再用所学的知识提出所需要的内容即可,完整代码如下:

# 有道翻译
import json
import urllib.request     # 先引用必要的模块
import urllib.parse
content = input('请输入你要查找的内容:')   # 接收所要查询的内容
# 这个数据表格是我们在网页内得到的
data = {
    'i': content,
    'from': 'AUTO',
    'to': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': '16080848522314',
    'sign': '4411bb288b085cd52841d65ddde0d8f8',
    'lts': '1608084852231',
    'bv': '03c7fe57b6c3c6df93436a3d08a92a66',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'
}

'''
TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.
'''
data = urllib.parse.urlencode(data)  # 要把data进行编译一下
data = bytes(data,encoding='utf-8')  # 而且要把data转换成字节类型,并且要编译,不然会报错如上面注释。
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
# http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
# 在这里我们要删掉_o,不然的话会报错:{"errorCode":50},我们暂时这样处理,就不会报错了。以后学了js逆向后再解释。

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36X-Requested-With:XMLHttpRequest'} # 用soft wrap功能可以换行
# 以下代码是请求以及获取数据:
req = urllib.request.Request(url,data=data,headers=headers) # 将url,data,headers都当成参数传入
res = urllib.request.urlopen(req)
html = res.read().decode('utf-8')
r_dict = json.loads(html) # 把字符串转换成字典
# print(r_dict)
'''
{'type': 'ZH_CN2EN', 'errorCode': 0, 'elapsedTime': 0, 'translateResult': [[{'src': '你好', 'tgt': 'hello'}]]}
'''
res_words = r_dict['translateResult'][0][0]['tgt']
print('翻译结果:',res_words)

我在提示中输入“你好”,执行结果是:

请输入你要查找的内容:你好
翻译结果:hello 

我在提示中输入“hello”,输出结果是:

请输入你要查找的内容:hello
翻译结果: 你好

3. 第三方模块requests

需要先安装这个模块
在这里插入图片描述

3.1 用requests模块爬取某官网数据

下面我用这个模块爬取当当网官网数据,注意看注释:

# requests模块
import requests
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36X-Requested-With:XMLHttpRequest'} # 用soft wrap功能可以换行
# 下面是当当网的官网
url = 'http://book.dangdang.com/?_utm_brand_id=11106&_ddclickunion=460-5-biaoti|ad_type=0|sys_id=1'
response = requests.get(url,headers=headers)
# response.encoding='gbk'
# result = response.text
# print(result)
# 或者用如下方法
result = response.content.decode('gbk')
print(result)

3.2 用requests模块发送post请求

我们还将上面的有道翻译项目再使用requests模块做一遍:

# 用requests模块做有道翻译项目
import json
import requests
content = input('请输入你要查找的内容:')   # 接收所要查询的内容
data = {
    'i': content,
    'from': 'AUTO',
    'to': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': '16080848522314',
    'sign': '4411bb288b085cd52841d65ddde0d8f8',
    'lts': '1608084852231',
    'bv': '03c7fe57b6c3c6df93436a3d08a92a66',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'
}
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36X-Requested-With:XMLHttpRequest'} # 用soft wrap功能可以换行

url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
res = requests.post(url,data=data,headers=headers)
html = res.text
r_dict = json.loads(html) # 把字符串转换成字典
res_words = r_dict['translateResult'][0][0]['tgt']
print('翻译结果:',res_words)

我执行代码,并再提示中输入:hello world执行结果为

请输入你要查找的内容:hello world
翻译结果: 你好,世界

我们发现这个模块非常的简便,不需要再那么多的编译和转化了。步骤简单,所以以后推荐使用这个方法。

3.3 requests模块源码查看

可以直接去Github上下载源码:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
确实写得很牛。可以学习和借鉴。
本次博文到此结束。谢谢观看!

猜你喜欢

转载自blog.csdn.net/m0_46738467/article/details/111185197