欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

urllib爬虫(流程+案例)

程序员文章站 2022-03-18 14:53:38
网络爬虫是一种按照一定规则自动抓取万维网信息的程序。在如今网络发展,信息爆炸的时代,信息的处理变得尤为重要。而这之前就需要获取到数据。有关爬虫的概念可以到网上查看详细的说明,今天在这里介绍一下使用urllib进行网络爬虫的方法使用,在最后的一个案例中把最基本的爬虫要素运用进去,可以作为初学者的一个模 ......

  网络爬虫是一种按照一定规则自动抓取万维网信息的程序。在如今网络发展,信息爆炸的时代,信息的处理变得尤为重要。而这之前就需要获取到数据。有关爬虫的概念可以到网上查看详细的说明,今天在这里介绍一下使用urllib进行网络爬虫的方法使用,在最后的一个案例中把最基本的爬虫要素运用进去,可以作为初学者的一个模板,读懂它进行适当修改就可以使用。

  以我的经验来看,在编程上对于陌生的简单的东西,最快的学习方法就是从代码入手了。当然有些很厉害的兄弟,可以完全忽略我这篇博客了。下面的内容我尽量将注释写在代码当中。

1、urllib爬取网页

  下面是通过urllib的request函数来获取网页信息,现在的request库也很方便,不过原理都是一样的。

 1 import urllib.request
 2 
 3 # 向指定的url地址发送请求并返回服务器响应的数据(文件的对象)
 4 response = urllib.request.urlopen("http://www.baidu.com")
 5 
 6 # 读取文件的全部内容,会把读到的东西赋值给一个字符串变量
 7 data = response.read()
 8 print(data)  # 读取得到的数据
 9 print(type(data))  # 查看数据类型
10 
11 # 读取一行
12 data = response.readline()
13 
14 # 读取文件的全部内容,赋值给一个列表变量,优先选择
15 data = response.readlines()
16 # print(data)
17 print(type(data[100]))
18 print(type(data[100].decode("utf-8")))  # 转字符串
19 print(len(data))
20 
21 # 将爬取到的网页写入文件
22 with open(r"f:/python_note/爬虫/file/file1.html", "wb") as f:
23     f.write(data)
24 
25 
26 # response 属性
27 
28 # 返回当前环境的有关信息
29 print(response.info())
30 
31 # 返回状态码
32 print(response.getcode())
33 # 200为正常,304位为有缓存
34 
35 # 返回当前正在爬取的url地址
36 print(response.geturl())
37 
38 url = "https://www.sogou.com/sgo?query=凯哥学堂&hdq=sogou-wsse-16bda725ae44af3b-0099&lxod=0_16_1_-1_0&lxea=2-1-d-9.0.0.2502-3-cn1307-0-0-2-e96f3d19f4c66a477ce71fd168dd223d-62&lxoq=kaigexuetang&lkx=0&ie=utf8"
39 url2 = r"https%3a//www.sogou.com/sgo%3fquery%3d%e5%87%af%e5%93%a5%e5%ad%a6%e5%a0%82%26hdq%3dsogou-wsse-16bda725ae44af3b-0099%26lxod%3d0_16_1_-1_0%26lxea%3d2-1-d-9.0.0.2502-3-cn1307-0-0-2-e96f3d19f4c66a477ce71fd168dd223d-62%26lxoq%3dkaigexuetang%26lkx%3d0%26ie%3dutf8"
40 
41 newurl = urllib.request.quote(url)  # 将含汉字的编码
42 print(newurl)
43 newurl2 = urllib.request.unquote(url2)  # 解码
44 print(newurl2)
45 
46 
47 # 端口号,http  80
48 # https  443

2、爬取到的网页直接写入文件

  将网页信息写入文件可以通过上面的读取然后再写入文件,还有更简便的方法,就是爬取页面的同时写入文件,这个也不难,只是一个函数而已。相信应该可以明白下面的内容,filename后面的内容就是需要存储网页信息的文件路径。

1 import urllib.request
2 
3 urllib.request.urlretrieve("http://www.baidu.com",
4                            filename=r"f:/python_note/爬虫/file/file2.html")
5 
6 # urlretrieve在执行过程中,会产生一些缓存
7 # 清除缓存
8 urllib.request.urlcleanup()

3、模拟浏览器

  我们都知道,进行爬虫的时候,很在乎它的效率,计算机进行获取数据当然会比手动来的快。但是这样一来,你就占用了该网站的大部分带宽,导致其他人上网会很卡。因此,很多网站会有自己的反爬机制,有些只是简单的预防一下。通过网络爬虫进行访问时会有一个爬虫的请求头,那么,可以模拟一下浏览器来访问,也就是把请求头中的信息换成浏览器信息。网上可以找到很多,随便粘贴一个就好了。

 1 import random
 2 import urllib.request
 3 
 4 url = "http://www.baidu.com"
 5 
 6 '''
 7 # 模拟请求头 (这是一种方法,下面使用另一种方法)
 8 headers = {
 9     "user-agent": "mozilla/5.0 (windows nt 10.0; wow64) applewebkit/537.36 (khtml, like gecko) chrome/69.0.3493.3 safari/537.36"
10 }
11 # 设置一个请求体
12 req = urllib.request.request(url, headers=headers)
13 # 发起请求
14 response = urllib.request.urlopen(req)
15 data = response.read()
16 print(data)
17 '''
18 
19 agentslist = [
20     "mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/39.0.2171.95 safari/537.36 opr/26.0.1656.60",
21     "opera/8.0 (windows nt 5.1; u; en)",
22     "mozilla/5.0 (windows nt 5.1; u; en; rv:1.8.1) gecko/20061208 firefox/2.0.0 opera 9.50",
23     "mozilla/4.0 (compatible; msie 6.0; windows nt 5.1; en) opera 9.50",
24     "mozilla/5.0 (windows nt 6.1; wow64; rv:34.0) gecko/20100101 firefox/34.0 "
25 ]
26 
27 agentstr = random.choice(agentslist)  # 这里是从列表中随机取出一个浏览器信息来改写请求头,避免被网站发现同一个地址快速持续的访问它而被封掉
28 req = urllib.request.request(url)  # 里面添加头要写成键值对
29 # 向请求体里添加了user-agent
30 req.add_header("user-agent", agentstr)  # 这里添加时传入两个字符串,自动组合
31 
32 response = urllib.request.urlopen(req)
33 print(response.read())

4、设置超时

  当访问一直没有被响应时,我们需要让它继续往下进行而不是卡在那里。通过异常捕获来实现。

1 import urllib.request
2 
3 # 如果网页长时间未响应,系统判断超时,无法爬取
4 for i in range(1, 100):
5     try:
6         response = urllib.request.urlopen("http://www.baidu.com", timeout=0.1)
7         print(len(response.read()))
8     except:
9         print("time out")

5、http请求

  当然有些网站还需要先登录之类的,也就是不仅仅从上面获取信息,还需要上传一些东西,下面介绍一下发送请求的两种方法。

 1 '''
 2 使用场景:进行客户端与服务端之间的消息传递时使用
 3 get: 通过url网址传递信息,可以直接在url网址上添加要传递的信息(不安全)
 4 post: 可以向服务器提交数据,是一种比较流行,安全的数据传递方式
 5 put: 请求服务器存储一个资源,通常要指定存储的位置
 6 delete: 请求服务器删除一个资源
 7 head: 请求获取对应的http报头信息
 8 options: 可以获取当前url所支持的请求类型
 9 '''
10 
11 '''
12 get请求:
13 特点:把数据拼接到请求路径后面传递给服务器
14 优点:速度快
15 缺点:承载的数据量小,不安全
16 '''
17 
18 '''
19 post请求:
20 特点:把参数进行打包,单独传输
21 优点:数量大,安全(当对服务器数据进行修改时建议使用post)
22 缺点:速度慢
23 '''
24 import urllib.request
25 import urllib.parse  # 对请求打包的库
26 
27 url = "http://www.baidu.com"
28 # 将要发送的数据合成一个字典
29 # 字典的键去网址里找,一般为input标签的name属性的值
30 data = {
31     "username": "xiaoxiao",
32     "passwd": "999"
33 }
34 # 对要发送的数据进行打包
35 postdata = urllib.parse.urlencode(data).encode("utf-8")
36 
37 # 请求体
38 req = urllib.request.request(url, data=postdata)
39 
40 # 请求
41 response = urllib.request.urlopen(req)
42 print(response.data())

6、json数据解析

 1 '''
 2 概念:一种保存数据的格式
 3 作用:可以保存本地的json文件,也可以将json串进行传输,通常将json称为轻量级的传输方式
 4 xml可读性更强,但是有很多没有用的标签
 5 json文件组成:
 6 {}       代表对象(字典)
 7 []       代表列表
 8 :        代表键值对
 9 ,        分隔两个部分
10 '''
11 
12 import json
13 
14 # 将json格式的字符串转换为python数据类型的对象
15 
16 jsonstr = '{"name":"xiaoxiao", "age":18, "hobby":["money", "power", "english"], "parames":{"a":1, "b":2}}'
17 
18 jsondata = json.loads(jsonstr)
19 print(jsondata)
20 print(type(jsondata))
21 print(jsondata["hobby"])
22 
23 
24 jsondata2 = {"name": "xiaoxiao", "age": 18, "hobby": [
25     "money", "power", "english"], "parames": {"a": 1, "b": 2}}
26 # python类型的数据就是比json格式少个引号
27 
28 # 将python数据类型的对象转换为json格式的字符串
29 
30 jsonstr2 = json.dumps(jsondata2)
31 print(jsonstr2)
32 print(type(jsonstr2))

7、抓取网页动态ajax请求的数据

  经常浏览一些网页会有这种情况,就是首先加载出一个页面的内容,向下滚动还有内容,在最下面会有一个提示下拉获取更多内容这类的东西。这个可以让加载网页的速度更快,毕竟内容少了嘛,再我们想要看到更多信息时候再加载。对于这样的一部分页面爬取其实也很简单,细心观察一下每次多加载一块的页面时,这时候上方的网址变化可以发现,有些是有数字变化的。可以根据里面的具体规律来修改每次请求的信息。

 1 import urllib.request
 2 import ssl
 3 import json
 4 
 5 
 6 def ajaxcrawler(url):
 7     headers = {
 8         "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"
 9     }
10     req = urllib.request.request(url, headers=headers)
11 
12     # 使用ssl创建未验证的上下文
13     context = ssl._create_unverified_context()  # 访问的是https
14 
15     response = urllib.request.urlopen(req, context=context)
16     jsonstr = response.read().decode("utf-8")
17     print(type(response.read()))  # byte型
18     print(type(response.read().decode("utf-8")))  # json字符串型
19     jsondata = json.loads(jsonstr)
20     return jsondata
21 
22 
23 # url = "https://movie.douban.com/j/chart/top_list?type=17&interval_id=100%3a90&action=&start=0&limit=20"
24 # info = ajaxcrawler(url)
25 # print(info)
26 
27 for i in range(1, 11):
28     url = "https://movie.douban.com/j/chart/top_list?type=17&interval_id=100%3a90&action=&start=" + \
29         str(i * 20) + "&limit=20"
30     info = ajaxcrawler(url)
31     print(len(info))

8、糗事百科爬虫

 1 import urllib.request
 2 import re
 3 
 4 # https://www.qiushibaike.com/text/page/2/
 5 
 6 
 7 def jokecrawler(url):
 8     headers = {
 9         "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"
10     }
11     req = urllib.request.request(url, headers=headers)
12     response = urllib.request.urlopen(req)
13 
14     html = response.read().decode("utf-8")
15     # print(type(html))
16 
17     pat = r'<div class="author clearfix">(.*?)<span class="stats-vote"><i class="number">'
18     re_joke = re.compile(pat, re.s)  # re.s 使可以匹配换行
19     divslist = re_joke.findall(html)
20     # print(divslist)
21     # print(len(divslist))
22 
23     dic = {}
24     for div in divslist:
25         # 用户名
26         re_u = re.compile(r"<h2>(.*?)</h2>", re.s)
27         username = re_u.findall(div)
28         username = username[0].rstrip()
29         # print(username)
30         # 段子
31         re_d = re.compile(r'<div class="content">\n<span>(.*?)</span>', re.s)
32         duanzi = re_d.findall(div)
33         duanzi = duanzi[0].strip()
34         # print(type(duanzi))
35         dic[username] = duanzi
36     return dic
37 
38     # with open(r"f:/python_note/爬虫/file/file2.html", "w") as f:
39     #     f.write(html)
40 
41 
42 url = "https://www.qiushibaike.com/text/page/1/"
43 info = jokecrawler(url)
44 for k, v in info.items():
45     print(k + ':\n' + v)