3.简单的网页爬虫开发

目录

一、爬虫开发中的法律与道德问题

1.数据采集的法律问题

(1)妨害个人信息安全

(2)涉及国家安全信息

(3)妨害网站正常运行

(4)侵害他人利益

(5)内幕交易

2.道德协议

(1)Robots协议

(2)不要开源爬虫的源代码

二、Requests库的使用

1.requests介绍

2.requests安装

3.使用requests获取网页内容

(1)get方法

(2)post方法

(3)get方法和post方法的区别

三、使用Requests与正则表达式获取网页内容

1.分析网页结构

2.分段提取

3.提取小说标题

4.提取小说网址

5.提取作者信息

6.单页提取完整代码

7.多页提取完整代码

四、作业

参考文献


从这一章开始,我们将学习使用网络爬虫直接从互联网获取数据,为了避免掉坑,我们先简要探讨爬虫开发中的法律与道德问题,为自己树立底线,既不侵害他人利益,也更好地保护自己。

一、爬虫开发中的法律与道德问题

科学技术是一把锋利无比的双刃剑,向善向恶,关键在于使用者的选择。网络爬虫本身是一项从互联网快速精准获取数据信息的基础性技术,在处理体量庞大的网络数据工作上具有极高的价值。但是也有些爬虫不遵守规则,随心所欲地爬取别人不愿意分享的数据信息,并大量挤占服务器资源,变成了“网络害虫”。

1.数据采集的法律问题

近年来,国家多部法律、法规对数据信息的采集、使用、传播行为的合理范围进行了规范,网络爬虫不再是游走在法律边缘的灰色产业,而变得有法可循。

(1)妨害个人信息安全

“自然人的个人信息受法律保护”写入《中华人民共和国法典》,非法收集、传播、买卖他人个人信息将负法律责任。如果发现爬虫收集到的海量信息中包含了敏感的他人个人信息,如涉及违法的应立即停止爬取,对相关代码进行修正并立即删除收集到的他人个人信息。

自然人的个人信息受法律保护。任何组织或者个人需要获取他人个人信息的,应当依法取得并确保信息安全,不得非法收集、使用、加工、传输他人个人信息,不得非法买卖、提供或者公开他人个人信息。《中华人民共和国民法典》

(2)涉及国家安全信息

根据《中华人民共和国刑法》第二百八十五条规定,非法侵入计算机系统罪,是指违反国家规定,侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统的行为。

如果信息数据涉及国家关键信息基础设施,又需向境外提供时,应通过国家有关部门的安全评估。(详见《中华人民共和国网络安全法》第三十七条)

关键信息基础设施的运营者在中华人民共和国境内运营中收集和产生的个人信息和重要数据应当在境内存储。因业务需要,确需向境外提供的,应当按照国家网信部门会同国务院有关部门制定的办法进行安全评估;法律、行政法规另有规定的,依照其规定。《中华人民共和国网络安全法》第三十七条

(3)妨害网站正常运行

网络爬虫访问系统时,会占用网站的服务器资源,如果爬虫频繁巨量访问某一网站,就会占用服务器大量资源,甚至阻碍服务器的正常运行。在《数据安全管理办法(征求意见稿)》中对此行为也有明文规定。

网络运营者采取自动化手段访问收集网站数据,不得妨碍网站正常运行;此类行为严重影响网站运行,如自动化访问收集流量超过网站日均流量三分之一,网站要求停止自动化访问收集时,应当停止。《数据安全管理办法(征求意见稿)》第十六条

(4)侵害他人利益

公开的数据不一定被允许用于第三方盈利目的。例如未经版权方许可,就下载、传播某个网站的公开信息又用于盈利,就可能面临法律风险。

网络运营者分析利用所掌握的数据资源,发布市场预测、统计信息、个人和企业信用等信息,不得影响国家安全、经济运行、社会稳定,不得损害他人合法权益。《数据安全管理办法(征求意见稿)》第三十二条

(5)内幕交易

如果通过爬虫抓取某公司网站的公开数据,分析以后发现这个公司的股票具有投资价值,然后自己买入该公司股票并获利,这是合法的。

如果通过爬虫抓取某公司网站的公开数据,分析以后发现这个公司的股票具有投资价值,然后将分析结果和数据卖给某基金公司,从而获得销售收入,这也是合法的。

如果通过爬虫抓取某公司网站的公开数据,分析以后发现这个公司的股票具有投资价值,首先将分析结果和数据卖给某基金公司,然后自己又买入被爬取公司的股票并获利。此时,该行为涉嫌内幕交易,属于严重违法。[1]

这里有一篇文章就爬虫行为违规受罚的案例进行了探讨,建议大家了解,文章名称是《写了一段爬虫,效果极佳,公司200多人被抓!

2.道德协议

(1)Robots协议

Robots协议是网站跟爬虫间的协议,用简单直接的txt格式文本方式告诉对应的爬虫被允许的权限,也就是说robots.txt是搜索引擎中访问网站的时候要查看的第一个文件。当一个搜索蜘蛛访问一个站点时,它会首先检查该站点根目录下是否存在robots.txt,如果存在,搜索机器人就会按照该文件中的内容来确定访问的范围;如果该文件不存在,所有的搜索蜘蛛将能够访问网站上所有没有被口令保护的页面。

图1 知乎网站的Robots.txt

这个Robots.txt文件表示,对于任何爬虫,允许爬取除了以Disallow开头的网址以外的其他网址。但是Robots协议只是“君子协定”,不具有法律效力。该协议代表的更多的是一种契约精神, 互联网企业只有遵守这一规则,才能保证网站及用户的隐私数据不被侵犯。违背Robots协议将带来巨大安全隐忧。百度曾因360违反百度的Robots协议而起诉360.

图2 当年百度起诉奇虎违反Robots协议

(2)不要开源爬虫的源代码

开源是一件好事,但不要随便公开爬虫的源代码。因为别有用心的人可能会拿到被公开的爬虫代码而对网站攻击或者恶意抓取数据。

二、Requests库的使用

1.requests介绍

关于requests的介绍,在requests的官网上是这么说的“Requests is an elegant and simple HTTP library for Python, built for human beings.”意思是requests是一款优雅简洁的Python HTTP库,为人类所建。Requests还有一个副标题“HTTP for humans”(“这才是给人用的HTTP库”)。另外,大家可以了解下requests的中文版介绍,幽默感十足。

Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。

警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症、冗余代码症、重新发明轮子症、啃文档症、抑郁、头疼、甚至死亡。[2]

Python系统自带的urllib和urllib2库也可以获取网页内容,但使用起来并不是那么方便。使用Requests发送HTTP1.1请求极为容易。不需要手动向URL添加查询字符串,也不需要对POST数据格式化。Keep-alive和HTTP链接池百分百实现自动化,这些都得益于底层urllib3的支持。

Requests满足今日web的所有需求,Requests支持HTTP的特性包括:

保持活动和
连接池
国际域名
和URL
Cookie
持久性会话
浏览器式SSL验证自动内容解码基本/摘要身份验证优雅的键/值Cookie自动减压
Unicode
响应机构
HTTP(S)
代理支持

分段文件

上传

流下载连接超时分块请求.netrc支持线程安全

2.requests安装

使用pip安装requests库,在终端或命令窗口中输入以下代码:

pip install requests
图3 requests自动安装过程

安装完成后,在python或pycharm的交互环境中,输入import requests,如果不报错,则说明安装成功。

图4 测试requests是否安装成功

3.使用requests获取网页内容

(1)get方法

get方法主要从服务器获取信息。要实现一个简单的网页链接,需要至少用到两样东西,一是请求方式:例如.get()、.post()、.head()、.put()等方法,二是需要链接的url地址,然后将url作为请求方法中的参数。这里以get函数为例,当执行后我们会获得服务器的一个响应,如果将它输出会看到<Response [200]>,括号内的200是HTTP状态代码status code。

import requests

url = "http://www.baidu.com"
response = requests.get(url)
print(response)

# 输出
<Response [200]>

使用.status_code属性可以获取状态码。状态码是写在HTTP协议中的,在客户端与服务器端通信时,客户端发送请求,服务器端返回结果,同时返回状态值,告诉用户这次请求是成功了还是失败了。《常见的HTTP状态码》。

import requests

url = "http://www.baidu.com"
response = requests.get(url)
status_code = response.status_code
print(status_code)

# 输出
200

第4行使用.content属性获取bytes型网页源码,第5行使用.decode()方法将bytes型网页源码解码为字符串型网页源码。

图5 获得网页源码

之所以要将bytes码转为字符串型码,是由于中文在bytes码下无法正常显示。这两行内容可以合并为一行。 

import requests
url = "http://www.baidu.com"
response = requests.get(url)
content_stirng = response.content.decode()
print(content_stirng)

decode()中的参数用以指定编码格式,如果缺省则默认使用UTF-8编码格式将字节型解码为字符串型的源代码。有一些网页可能不是UTF-8编码,这就需要在括号内注明编码格式的名称。

图6 在网页源码中查看网页编码格式

 

图7 使用gb2312编码的网页,但不知道为什么实际却要用gb18030解码

 以下是对不同编码格式的网页按格式解码。

import requests
sina_url = "http://www.sina.com.cn"
jb51_url = "https://www.jb51.net"
sina_html = requests.get(sina_url).content.decode('utf-8')
print(sina_html)

jb51_html = requests.get(jb51_url).content.decode('gb18030')
print(jb51_html)

常见的编码有ASCII、GBK、GB2312、GB18030、Unicode、UTF-8等等,关于这些编码的关系有一篇文章讲的很有意思,推荐阅读。但可惜只有转载,原文链接打不开了。《ASCII、Unicode、GBK和UTF-8字符编码的区别联系》

使用requests的content和text属性都可以返回页面内容,但它们两者也有一定区别。content返回的是字节码,如果需要正常显示需要decode重新解码成字符串。而text返回的是Unicode处理过的字符串,它会根据页面header中的charset解码,如果charset中找不到,则会调用chardet模块来推测编码格式。从存储来讲,content保存的是源码,它比text更加节省空间。但是text的解码不一定完全正确,就需要使用content.decode重新编码了。

使用chardet来推测编码格式:

import requests
import chardet
sina_url = "http://www.sina.com.cn"
jb51_url = "https://www.jb51.net"
sina_html = requests.get(sina_url).content
print(chardet.detect(sina_html))

jb51_html = requests.get(jb51_url).content
print(chardet.detect(jb51_html))

# 输出
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}

接下来你是不是也想到了利用chardet.detect中‘encoding’的值来帮助完成content的解码呢?这里可以建议你自己探索一下,然后你看看又会发现什么。

(2)post方法

post方法主要向服务器传送数据。以下我们在http://httpbin.org/网站中进行测试。

httpbin.org 这个网站能测试 HTTP 请求和响应的各种信息,比如 cookie、ip、headers 和登录验证等,且支持 GET、POST 等多种方法,对 web 开发和测试很有帮助。

有些网页必须使用指定的请求方式来获取内容,例如:http://httpbin.org/post只允许使用post方法,否则出现405错误。

# 使用了错误的访问方式
import requests
import json

url = 'http://httpbin.org/post'

response = requests.get(url).content.decode()
print(response)

# 输出
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>

使用post方法正常获取网页源代码

import requests
import json

url = 'http://httpbin.org/post'

response = requests.post(url).content.decode()
print(response)

# 输出
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "0", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.25.1", 
    "X-Amzn-Trace-Id": "Root=1-6054bac9-3536341b67d231c2571c3eb9"
  }, 
  "json": null, 
  "origin": "***.***.**.*", 
  "url": "http://httpbin.org/post"
}

使用post方法向form中提交信息,并获取网页源代码

import requests
import json

url = 'http://httpbin.org/post'
data = {
    'key1':'value1',
    'key2':'value2'
}
response = requests.post(url,data = data).content.decode()
print(response)

# 输出
{
    "args":{},
    "data":"",
    "files":{},
    "form":{
        "key1":"value1",
        "key2":"value2"
    },
    "headers":{
        "Accept":"*/*",
        "Accept-Encoding":"gzip, deflate",
        "Content-Length":"23",
        "Content-Type":"application/x-www-form-urlencoded",
        "Host":"httpbin.org",
        "User-Agent":"python-requests/2.25.1",
        "X-Amzn-Trace-Id":"Root=1-6054b70b-073d1a773c27f3fa1d91862d"
    },
    "json":null,
    "origin":"***.***.**.*",  # ‘*’部分为IP
    "url":"http://httpbin.org/post"
}

(3)get方法和post方法的区别

  • get方法的主要作用是从服务器获取信息,也可以传递部分信息给服务器,而这些信息也是告诉服务器用户想要啥。
  • 使用get方法向url传递参数。get方法在通过URL提交数据,数据在URL中可以看到;post方法,数据放置在HTML HEADER内提交。
url_get = 'http://httpbin.org/get'
param = {
    'key1': 'value1',
    'key2': 'value2'
}
response = requests.get(url_get,params=param)
print(response.url)

# 输出
http://httpbin.org/get?key1=value1&key2=value2 # 提交的参数在url中可以看到
  •  get方法由于受到URL长度的限制,不同浏览器对其有不同限制。post传输的数据量大,理论上没有限制。[3]

三、使用Requests与正则表达式获取网页内容

实例:提取起点中文网完本小说基本信息。本次实战仅供交流学习,支持原创,请上起点中文网订阅观看。

主要任务:分析网页结构,使用requests获取网页源代码,用正则表达式表达规律并提取小说标题、网址与作者信息,将提取到的信息保存到csv文件中。

1.分析网页结构

图8 分析网页结构

2.分段提取

正则表达式:'li data-rid(.*?)</em'

3.提取小说标题

正则表达式:'data-bid="\\d*">(.*?)</a'

4.提取小说网址

正则表达式:'href="(.*?)" data-bid'

5.提取作者信息

正则表达式:'class="author".*?_blank">(.*?)</a>'

6.单页提取完整代码

import requests
import csv
import re

url = 'https://www.qidian.com/finish'
content_list = []
reponse = requests.get(url).content.decode('utf-8')
content_list_1 = re.findall('li data-rid(.*?)</em',reponse,re.S)

for content in content_list_1:
    result = {}
    result['title'] = re.findall('data-bid="\\d*">(.*?)</a',content,re.S)[0]
    result['url'] = 'https:' + re.findall('href="(.*?)" data-bid',content,re.S)[0]
    result['author'] = re.findall('class="author".*?_blank">(.*?)</a>',content,re.S)[0]

    content_list.append(result)

with open('qidian_finish.csv','w',encoding='utf-8-sig') as f:
    writer =csv.DictWriter(f,fieldnames=['title','url','author'])
    writer.writeheader()
    writer.writerows(content_list)

7.多页提取完整代码

import requests
import csv
import re
url = "https://www.qidian.com/finish?action=hidden&orderId=&style=1&pageSize=20&siteid=1&pubflag=0&hiddenField=2&page="
content_list = []
for page in range(1,6):
    reponse = requests.get(url+str(page)).content.decode('utf-8')

    content_list_1 = re.findall('li data-rid(.*?)</em',reponse,re.S)

    for content in content_list_1:
        result = {}
        result['title'] = re.findall('data-bid="\\d*">(.*?)</a',content,re.S)[0]
        result['url'] = 'https:' + re.findall('href="(.*?)" data-bid',content,re.S)[0]
        result['author'] = re.findall('class="author".*?_blank">(.*?)</a>',content,re.S)[0]

        content_list.append(result)

with open('qidian_finish.csv','w',encoding='utf-8-sig') as f:
    writer =csv.DictWriter(f,fieldnames=['title','url','author'])
    writer.writeheader()
    writer.writerows(content_list)
图9 数据保存到csv文件中的效果

四、作业

在努努书坊(https://www.kanunu8.com/)中找到一篇自己喜欢的小说,例如金庸系列、四大名著等,使用requests库和正则表达式,将小说目录中的章节网址和章节名称爬取下来,并保存在csv中。作业需要提交的文件:.py文件、.csv文件。

参考文献

[1]Python爬虫开发从入门到实践.谢乾坤.人民邮电出版社

[2]Requests document.https://requests.readthedocs.io/zh_CN/latest/index.html

[3]post传输数据大小.https://blog.csdn.net/w8998036/article/details/105971328

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡老师11452

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值