前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >爬虫 | urllib入门+糗事百科实战

爬虫 | urllib入门+糗事百科实战

作者头像
小小詹同学
发布2021-04-19 11:34:22
3470
发布2021-04-19 11:34:22
举报
文章被收录于专栏:小詹同学小詹同学

所谓爬虫(crawler),是指一只小虫子,在网络中爬行,见到有用的东西就会把它拿下来,是我们获取信息的一个重要途径。平常使用的浏览器,它的背后就是一个巨大的爬虫框架,输入我们想要查找的信息,帮我们爬取下来。今天就从较为简单的urllib爬虫开始介绍。

Urllib库是python内置的一个爬虫库,现在常用的有requests,它是对urllib进行了进一步的封装,今天先从urllib入手,后续再聊requests等的使用。根据我的风格来说,当然是有实际操作大家更容易理解,所以说,本文仍然是从代码入手,带你实现第一个爬虫小栗子。

官方的介绍如下:

urllib is a package that collects several modules for working with URLs:

  • urllib.request for opening and reading URLs
  • urllib.error containing the exceptions raised by urllib.request
  • urllib.parse for parsing URLs
  • urllib.robotparser for parsing robots.txt files

上面的四块其实很容易理解,分别是请求内容、异常处理、URL解析以及robot协议解析。不过今天不介绍那么多,有疑问的话可以自行查询相应的内容,今天的任务是入门,以及实现一个小爬虫。

发送请求

代码语言:javascript
复制
# 导入请求库
import urllib.request

# 向指定的url地址发送请求并返回服务器响应的数据(文件的对象)
response = urllib.request.urlopen("http://www.baidu.com")

# 读取文件的全部内容,会把读到的东西赋值给一个字符串变量
data = response.read()

简单三行代码就得到了我们所要的内容,可以查看一下data中的信息,其实这就形成了我们在浏览器中看到的内容,可以通过浏览器页面F12查看。

response是我们请求百度首页返回的响应,可以通过这个响应查看这次请求的一些信息。例如:

代码语言:javascript
复制
response.info() 返回当前环境的一些信息(日期、cookies等)
response.getcode() 返回状态码(200代表正常访问等)
response.geturl() 返回正在爬取的地址

写入文件

其实获取到信息,存储到文件就很方便了,可以参考【python文件操作】,不过在urllib库中还有一个直接将爬取到的内容存到文件的方法。

代码语言:javascript
复制
import urllib.request

urllib.request.urlretrieve("http://www.baidu.com",
                           filename=r"F:/demo/file.html")
# urlretrieve在执行过程中,会产生一些缓存
# 清除缓存
urllib.request.urlcleanup()

模拟浏览器

现在爬虫发展的非常快,而爬虫给网站带来的压力也不小,因此,越来越多的网站在研究它的反爬机制。也就是发现你是一个爬虫而非人工的访问,并且对自己的网站造成压力等,那么就会采取措施,比如禁止你的访问、封掉你的IP等等。说这些什么意思呢?既然人家不让爬,那么我们可以伪装一下,假装自己是正常访问。当然这也是不容易的,不过有一些最基本的操作,还是可以轻松理解的。

对于使用python来进行爬虫,其实是可以直接看到你是一个python爬虫的,直接告诉人家是个爬虫,那想禁你还不轻松。因此,首先针对这个问题,可以采用模拟浏览器的方式来解决。在发起请求后,请求头中包含一个user-agent字段,修改这个内容就可以了。

代码语言:javascript
复制
import urllib.request

url = "http://www.baidu.com"

# 模拟请求头
headers = {
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3493.3 Safari/537.36"
}

# 设置一个请求体
req = urllib.request.Request(url, headers=headers)

# 发起请求
response = urllib.request.urlopen(req)

关于User-Agent在网上可以找到很多,或者打开自己的浏览器,F12->network,随便点一个网页找request headers即可。

超时设置

在爬虫的过程中难免会遇到请求不到内容的情况,当它无法继续爬取的时候我们也不能一直和它耗着不是,而且如果是爬虫期间的某一个地址访问不到,也不能让它影响后面的工作,因此,设置超时是有必要的。操作也很方便,只需要在打开页面的时候添加个timeout参数即可。

代码语言:javascript
复制
import urllib.request

# 如果网页长时间未响应,系统判断超时,无法爬取
try:
    response = urllib.request.urlopen("http://www.baidu.com", timeout=0.1)
except:
    print("time out")

HTTP请求

主要的HTTP请求有以下几种,最常用的就是get和post。

GET: 通过url网址传递信息,可以直接在url网址上添加要传递的信息(不安全) POST: 可以向服务器提交数据,是一种比较流行,安全的数据传递方式 PUT: 请求服务器存储一个资源,通常要指定存储的位置 DELETE: 请求服务器删除一个资源 HEAD: 请求获取对应的http报头信息 OPTIONS: 可以获取当前url所支持的请求类型

  • get请求:

特点:把数据拼接到请求路径后面传递给服务器

优点:速度快

缺点:承载的数据量小,不安全

  • post请求:

特点:把参数进行打包,单独传输

优点:数量大,安全(当对服务器数据进行修改时建议使用post)

缺点:速度慢

下面举个栗子,这就需要用到开始提到的第二个方法parse。

代码语言:javascript
复制
import urllib.request
import urllib.parse # 对请求打包的库

url = "http://httpbin.org/post"
# 将要发送的数据合成一个字典
data = {
    "name": "xiaotian"
}
# 对要发送的数据进行打包
postdata = urllib.parse.urlencode(data).encode("utf-8")

# 请求体
req = urllib.request.Request(url, data=postdata)

# 请求
response = urllib.request.urlopen(req)
print(response.read())

实战演练

开始写程序之前,一定要先分析网页。选取糗事百科的段子来爬一下,网址在这(https://www.qiushibaike.com/text/)。

既然是爬取上面的段子,首先要找到段子对应网页中的什么位置,打开F12(前面一直说F12,其实就是打开网页的源码),左上角有个箭头,可以点击它,用来快速找到网页显示部分与源码的对应。

可以看到上方,鼠标所在位置的颜色可以对应找到源码。找到一个段子的源码,那紧接着就是找我们想要的内容,例如发布段子的用户名,以及段子的内容等。当然,今天的内容都是初级的爬虫,想要的信息都在这样一个静态网页中,找到如下的内容,然后利用正则表达式来提取其中的信息。【正则表达式

代码语言:javascript
复制
import urllib.request
import re

def jokeCrawler(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10"
    }
    req = urllib.request.Request(url, headers=headers)
    response = urllib.request.urlopen(req)

    html = response.read().decode("utf-8")

    pat = r'<div class="author clearfix">(.*?)<span class="stats-vote"><i class="number">'
    re_joke = re.compile(pat, re.S) # re.S 使可以匹配换行
    divsList = re_joke.findall(html)

    dic = {}
    for div in divsList:
        # 用户名
        re_u = re.compile(r"<h2>(.*?)</h2>", re.S)
        username = re_u.findall(div)
        username = username[0].rstrip()
        # 段子
        re_d = re.compile(r'<div class="content">\n<span>(.*?)</span>', re.S)
        duanzi = re_d.findall(div)
        duanzi = duanzi[0].strip()
        dic[username] = duanzi
    return dic

url = "https://www.qiushibaike.com/text/page/1/"
info = jokeCrawler(url)
for k, v in info.items():
    print(k + ':\n' + v)

上面我所做的内容比较粗糙,可以自行再处理一下正则表达式。这只是爬取了一页的内容,尝试把URL中的page换个数字就会发现,可以做到翻页,假如使用循环,可以爬虫更多的内容,后面就可以自行探索了。

推荐阅读

误执行了rm -fr /*之后,除了跑路还能怎么办?!

程序员必备58个网站汇总

大幅提高生产力:你需要了解的十大Jupyter Lab插件

代码语言:javascript
复制
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小詹学Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档