4.1)urllib介绍,获得网页内容<br>
4.2)介绍Beautiful Soup<br>
4.3)实战<br>
2.URL
在开始前,有必要介绍下URL,因为URL是一切开端;
简单的来讲,URL就是在浏览器端输入的 http://www.baidu.com 这个字符串。
通俗地说,URL是Internet上描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上。
采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。
URL的一般格式为(带方括号[]的为可选项):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
URL的格式由三部分组成:
①第一部分是协议(或称为服务方式)。
②第二部分是存有该资源的主机IP地址(有时也包括端口号)。
③第三部分是主机资源的具体地址,如目录和文件名等。
第一部分和第二部分用“://”符号隔开,
第二部分和第三部分用“/”符号隔开。
第一部分和第二部分是不可缺少的,第三部分有时可以省略。
例:http://www.rol.cn.net/talk/talk1.htm
其计算机域名为www.rol.cn.net。
超级文本文件(文件类型为.html)是在目录/talk下的talk1.htm。
这是瑞得聊天室的地址,可由此进入瑞得聊天室的第1室。
例:file://ftp.yoyodyne.com/pub/files/foobar.txt
上面这个URL代表存放在主机ftp.yoyodyne.com上的pub/files/目录下的一个文件,文件名是foobar.txt。
爬虫最主要的处理对象就是URL,会根据URL地址取得所需要的文件内容,然后对它进行进一步处理。
3.urllib
Python里有一个内置的urllib库,是学习爬虫的基础核心,而这个库的作用是向服务器发出请求并获得网页内容,也就是学习爬虫的第一步
由于用的是Python3,在Python3中只有唯一的urllib库,而在Python2是有区分urllib2和urllib
在使用之前,一起看看urllib库有什么东东
import urllib
print(dir(urllib))
输出的结果:
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'error', 'parse', 'request', 'response']
可以看到urllib除了以双下划线开头结尾的内置属性外,还有4个重要的属性,分别是error,parse,request,response。
这4个属性中最重要的当属request了,它完成了爬虫大部分的功能,我们先来看看request是怎么用的。
request的使用:
request请求最简单的操作是用urlopen方法,代码如下:
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com/')
result = response.read()
print(result)
运行结果如下:
b'<!DOCTYPE html>\n\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n...
看到后一脸懵逼,把全部内容copy出来看,也并非乱码,内容跟网页的源码是一致的,但为了美观点,在读取的时候改一下编码,就变成这样了(如果有编码问题,也是同样的处理方案):
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com/')
result = response.read().decode("uft-8")
print(result)
运行结果如下:
!DOCTYPE html>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta content="always" name="referrer">
从输出的结果来看,至少有点层次感了,而这个就是我们想要的网页内容啦,4行代码就能把网页内容输出,简单吧~
上面的几句,就能获取到网页信息,但如果想爬取视频/图片呢,如何处理?或者需要网页的一些信息,也怎么处理?
import urllib.request
head = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0
pic_url = "http://e.hiphotos.bdimg.com/album/h%3D370%3Bq%3D90/sign=c4164900fbf2b211fb2e8349fabb1405/d043ad4bd11373f0562c40eca40f4bfbfbed04b5.jpg"
request = urllib.request.Request(pic_url,headers=head)
response = urllib.request.urlopen(request)
result = response.read()
with open("ganglian.jpg","wb") as f :
f.write(result)
path = "jb.png"
urllib.request.urlretrieve(pic_url,path)
4.Request
对于一般的网站,上面几句就能获取网页信息,但对于企业而已,网页里的信息也是很重要的,他们会做一些手段,防止爬取,而这种情况,唯一的办法就是让自己装的更像浏览器。
首先,用浏览器看一个简单的请求,比如用的Chrome浏览器,
按F12->network,然后地址栏输入一个url打开网页,就可以查看request的headers,可以把这个浏览器的headers信息复制下来使用。
requests head信息,而head信息有哪些(图二)?
一次访问,是包含了很多信息,通常伪装的是User-Agent这块,那怎么做?
这时候就需要用到urllib.request下的Request方法了,这个方法常用的就是传两个参数,url跟header,而这个header就是我们要伪装的信息了,从上看可以到一些信息,那手法就是这样的:
import urllib.request
head = {
"Host":"www.baidu.com",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4843.400 QQBrowser/9.7.13021.400",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
request = urllib.request.Request("http://www.baidu.com",headers=head)
response = urllib.request.urlopen(request)
result = respone.read
print(response.read().decode(
而输出的结果跟上面的例子是一样的,不同的是,这里把header信息修改下,这样做的就好像真的是浏览器发送的一样;
cookie
什么叫cookie?指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据,这也意味着,如果想登录这些网站,那我们先手动登录一次,登录成功后,服务端会分配cookie,那我们把cookie也发送过去,就可以模拟成真正的用户了。
那,我们要怎么做才能把我们的cookie发送过去呢?
import urllib.request
import http.cookiejar
cookie=http.cookiejar.CookieJar()
handler=urllib.request.HTTPCookieProcessor(cookie)
opener=urllib.request.build_opener(handler)
response=opener.open("http://www.jianshu.com/")
for item in cookie:
print('name=',item.name)
print('value=',item.value)
这里遇到了个坑,pytohn3中是加载http.cookiejar,http.cookies模块,不是python2中的import cookielib。
注意CookieJar()是属于http.cookiejar模块,而不是http.cookies模块,否则会报错: 'module' object has no attribute 'CookieJar'
beautifulSoup
通过上面的方式,基本上能获取到大部分网站的html代码信息,那网页信息获取已经完成了,接下来就是数据解析了,解析用的较多的是Beautiful Soup、正则、xpath,正则很实用,但是需要记住匹配模式,入手成本高,那一起了解下bs是啥玩意把~
beautifulSoup “美味的汤,绿色的浓汤”
一个灵活又方便的网页解析库,处理高效,支持多种解析器。
利用它就不用编写正则表达式也能方便的实现网页信息的抓取
由此可见,bs是一个从html文件中提取数据的Python库,是爬虫利器~
bs库下载:
PyCharm直接安装: File -> Default Settings -> Project Interpreter 选择Python 3的版本 -> 点+号 -> 搜索beautifulsoup4 安装即可
其他方式的安装,自行查询~
from bs4 import BeautifulSoup
import urllib.request
head = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0
request = urllib.request.Request("http://www.baidu.com",headers=head)
response = urllib.request.urlopen(request)
result = response.read().decode("utf-8")
soup = BeautifulSoup(result)
print(soup.title)
如果想打开本地的html文件来创建对象,则这样处理:
soup = BeautifulSoup(open('jb.html'))
这里有一点需要注意下,直接这样print的话,虽然能执行,但是会看到一场错误,如下:
UserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("html.parser").
解决方案下面也列出了:
BeautifulSoup(YOUR_MARKUP})
to this:
BeautifulSoup(YOUR_MARKUP, "html.parser")
意思很明显,在创建对象时指定解析器,html.parser是内置的 html解析器,也可以用lxml.parser
四大对象种类
Beautiful Soup 将复杂HTML文档转换成一个复杂的树形结构,每个节点都是 Python 对象,所有对象可以归纳为4种:
NavigableString
BeautifulSoup
Comment
下面我们进行一一介绍:
1)Tag(标签)
Tag 是什么?通俗点讲就是 HTML 中的一个个标签,需要注意,只会返回所有内容中第一个符合要求的标签,例如:
<title>The Dormouse
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
上面的 title a 等等 HTML 标签加上里面包括的内容就是 Tag
print(soup.title)
print(soup.head)
print(soup.a)
print(soup.p)
对于tag来说,有两个重要的属性,是name和attrs
print soup.name
print soup.head.name
soup 对象本身比较特殊,它的 name 即为 [document],对于其他内部标签,输出的值便为标签本身的名称。
attrs
print soup.p.attrs
\#{'class': ['title'], 'name': 'dromouse'}
这里把P标签的所有属性都打印出来,得到的类型是一个字典,可以通过键取值(print(soup.p['class'])),也可以使用get方法通过传入属性的名称(print(soup.p.get('class'))
也可以对属性和内容进行修改,如soup.p['class'] = "jbtest",print(soup.p)
NavigableString(标签内部文字)
soup.p.string
BeautifulSoup(文档的全部内容)
跟Tag相像,可以分别获取它的类型、名称、属性
Comment(特殊类型的 NavigableString )
输出的内容不包括注释符号,但在使用前,需要判断下类型:
if type(soup.a.string)==bs4.element.Comment:
print soup.a.string
实战说明:
想爬取网上内容,简单了解下,大部分网页都是下面情况之一:
1)一个网页包括所有信息,不需要点击下一页(如果需要点击下一页的,其实原理也一样,只是在URL后面加个page即可)
2)没有分页功能,需要滑动到底部,才会继续加载
实战1:下载小说
因为全职高手出了TV版,觉得还不错,就沉迷小说了,前段时间听说有更新了,之前就是用浏览器打开网页小说,然后在线一页一页翻,刚好现在学了爬虫,试试看(坏笑)
网页链接:http://www.biqukan.com/2_2675/
打开网页看了下,下面红框里的内容就是需要的内容,点击发现里面还是一个网页,然后就是小说正文内容,那大致想了下,流程应该是这样的:
1)获取下图需要的网页信息,并且把每章小说的URL获取出来
2)打开小说的URL,把正文获取出来
3)获取小说的标题,把回去的正文写到本地
1)获取下图需要的网页信息,并且把每章小说的URL获取出来
打开网页,按F12打开开发者工具,选择Elements选项(默认就是这选项),然后点击Elements选项左边两个的图标按钮(如下图1),点击后,图标按钮会变蓝色,然后把鼠标移动到网页上,然后在需要的地方进行点击(如图2),点击后右边的Elements就会自动定位到这里区域上(如图3)
然后在Elements往上翻,发现这些信息都是在一个class叫listman里面,全局搜索了下,发现这个listman是唯一的,因此可以直接使用find_all直接查找这个叫listman,然后拿到一个对象,里面的内容就是listman下的
接下来是先把非a标签无关的过滤点,过滤后是这样的:
观察这个结果,发现前12章不是我想要的,看了下网页结构,前12章就是最新章节列表,但不是我们需要的,所以也要过滤下前12章过滤章节
到这里,每章的小说URL获取出来的;
2)打开小说的URL,把正文获取出来
小说URL:http://www.biqukan.com/2_2675/1008632.html,打开后继续按照刚刚的套路,F12,点击小说正文区域,得到的信息就是这堆正文是在一个叫showtxt的class里面且showtxt是全局唯一,也按照刚刚的套路获取,里面的东西就是我们想要的正文啦~(开心脸)
小说链接、小说名称、正文都有了,就可以进行读写了,至此,小说就保存下来啦~
但因为楼主用的是win10的系统,在实际操作上,遇到一个Windows特有的问题--编码问题,那就是在写文件的时候,会报错:
UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position 4033: illegal multibyte sequence
那解决方案就是在写的时候指定编码格式,比如encoding = 'utf-8'来解决问题
另外要注意,如果文件下载是指定目录,建议判断对应文件夹是否存在,不存在则先创建,否则也会报错
脚本代码如下:
import urllib.request
from bs4 import BeautifulSoup
from urllib import error
import os
novel_url = "http://www.biqukan.com/2_2675/"
novel_base_url = "http://www.biqukan.com/"
save_dir = "Novel/"
def get_download_url():
download_req = urllib.request.Request(novel_url)
download_res = urllib.request.urlopen(download_req,timeout=20)
download_content = download_res.read()
download_soup = BeautifulSoup(download_content,"html.parser")
listmain = download_soup.find_all(attrs={'class':'listmain'})
a_list = []
for i in listmain:
if 'a' not in str(i):
continue
for d in i.findAll('a'):
a_list.append(d)
result_list = a_list[12:]
return result_list
def get_download_content(c):
download_url = novel_base_url + c.attrs.get('href')
download_name = c.string
download_req = urllib.request.Request(download_url)
download_response = urllib.request.urlopen(download_req,timeout=20)
download_content = download_response.read()
download_soup = BeautifulSoup(download_content,'html.parser')
showtxt = download_soup.find_all(attrs={'class':'showtxt'})
for txt in showtxt:
save_novel(txt,save_dir+download_name+".txt")
def save_novel(txt,path):
if not os.path.exists(save_dir):
os.makedirs(save_dir)
with open(path,"w",encoding="utf-8") as f:
f.write(txt.get_text(strip=True))
except (error.HTTPError,OSError) as e:
print(str(e))
else:
print('download success :'+path)
if __name__ == '__main__':
novel_list = get_download_url()
for content in novel_list:
get_download_content(content)
爬取百度图片里的图片,网站特点:下滑会自动加载更多内容,没有上下一页的按钮
工作上经常需要用到图片,然后每次都要网上搜,而且还要去各种网站,比较麻烦,所以想着效果是:提供脚本输入关键字,然后在百度图片处进行相关下载到本地
思路就是:
1)用户执行脚本后,手动输入想输入的内容
2)拼接URL,进行爬取
3)获取HTML,拿到结果写入数据
说干就干,先打开百度图片首页:http://image.baidu.com/
随便搜索一个内容:钢之炼金术师
https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=111111&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E9%92%A2%E4%B9%8B%E7%82%BC%E9%87%91%E6%9C%AF%E5%B8%88&oq=%E9%92%A2%E4%B9%8B%E7%82%BC%E9%87%91%E6%9C%AF%E5%B8%88&rsp=-1
看了下链接,搜索的内容去哪里了?一脸懵逼后尝试查一下英文字符
在搜索个英文:test
https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=111111&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=test
这次能看出,word后面带的就是输入的内容了,因此想搜索什么,就把word后面的value修改对应的词就好啦~
但是,那上面的word 后面的这串是什么鬼?“%E9%92%A2%E4%B9%8B%E7%82%BC%E9%87%91%E6%9C%AF%E5%B8%88”
做个实验:
kw = urllib.request.quote("钢之炼金术师")
print(kw)
输出的结果:
%E9%92%A2%E4%B9%8B%E7%82%BC%E9%87%91%E6%9C%AF%E5%B8%88
嗯,发现这个结果跟上面的是一模一样的,而这个quote函数就是用于屏蔽特殊字符的,比如空格、中文等,因为URL只允许部分ASCLL(数字字母和部分符号),其他的字符(包括汉字)是不符合URL的标准,所以URL需要对这些字符进行URL编码,URL编码的方式是把需要编码的字符转化为 %xx 的形式。通常 URL 编码是基于 UTF-8 的,函数说明也提及到给予UTF-8进行encode~
回到重点,那拼接网页就是:....(前面一大坨)+word="想搜索的内容"
http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=%E9%92%A2%E7%82%BC%E5%A3%81%E7%BA%B8&pn=0&gsm=64&ct=&ic=0&lm=-1&width=0&height=0
看了下网页的结构,信息都在一个叫imgpage的class里面,而它的children里面,class是imgitem就是我们所需要的~
看了下,imgpage并不是唯一,但里面的内容都是我们需要的,因此我们需要提取所有class叫imgpage的内容
于是就写下了imgpage_list = get_url_soup.findAll(attrs={"class":"imgpage"}),结果执行后发现,尼玛,空的???
空就代表没有这个class,就想着把这个soup打印出来看,结果,惊呆了~
这尼玛,为什么打出来的是JS???例子1直接打印suop可是html的内容:
以为是代码哪里错了,反复检查,貌似都没问题啊,无助之下,只能求助,结果科普了下,例子1爬取的网站是静态的,在页面中右键查看源码就能看到图片中的位置,就能把页面源码保存后解析获取内容
但百度图片这个网站,选择图片是能显示图片的位置和样式,但是右键查看源码,发现都是JS,是没有任何链接信息,原因是因为,百度图片的网页是一个动态页面,它的网页原始数据其实是没有这个个图片,是通过运行JS,把这个图片的数据插入到网页的html标签里面,这样造成的结果是,按F12虽然能看到这个标签,但实际去获取的时候,是没有这个标签的,它只在运行时加载和渲染,那这种情况怎样才能把图片下载下来?答案是抓包!
首先说明下,通过JS去做,好处时可以异步去加载或者处理,而百度图片就是一个例子,因此要看的是异步的数据,还是原来的网页,F12,选择network,选择XRH~
XRH是什么?XHR 全称:XMLHttpRequest,提供了对 HTTP 协议的完全的访问,而ajax通过原生的XMLHttpRequest对象发出HTTP请求,得到服务器返回的数据后,再进行处理。
而ajax = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
因此明白了,Chrome的XRH是用来记录ajax的请求,而百度图片用的就是ajax,因此就是这XRH看数据了~
回到上文,选择XRH后,是没有数据的,刷新下网页,发现出现了一条请求,但是分析后发现没有什么作用,然后就模拟下用户行为,不停的下滑刷新图片,结果就发现不同下滑的时候,会重复出现一条类似一样的请求,点击请求后再点击Preview,看到是一个jsonshuj ,点开data,能看到这里面有30条数据,随意点击一条展开后发现,需要的数据就在这里面了,内容有多条url信息,手动打开后发现这几个URL都是可以下载所需的图片~
整理下信息,回头看,百度图片一开始只加载30张图片,当下滑时,页面会动态加载一条json数据,每次json数据里面包含30条信息,信息里面包含图片的URL,JS会把这些URL解析并显示,从而达到每次滚动底部又多出30张图片~
URL获取了,那怎么滑动操作呢?接下来就分析下,一直出现的json数据有没有规律?
点击Headers,对比请求信息,发现大多数字段都是保持不变,唯有pn字段是每次以30的步长递增,这跟上面说的30张图片不就对应的上吗?(坏笑)
当然,还有queryWord跟word的值都是想要搜索的内容,因此把请求的URL copy出来,到浏览器上访问:
在里面直接搜索图片的下载关键字,比如thumbURL,发现在能这个网页上查询到,并且图片正常,记下来就是直接用文本提取就好了
https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E9%92%A2%E4%B9%8B%E7%82%BC%E9%87%91%E6%9C%AF%E5%B8%88&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&word=%E9%92%A2%E4%B9%8B%E7%82%BC%E9%87%91%E6%9C%AF%E5%B8%88&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&pn=60&rn=30&gsm=3c&1524867815458=
基本上,流程已经分析完了,贴上源码
import urllib.request
from bs4 import BeautifulSoup
import urllib.parse
import re
import os
path = "pic/"
import json
pic_url = "https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E9%92%A2%E4%B9%8B%E7%82%BC%E9%87%91%E6%9C%AF%E5%B8%88" \
"&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&word=%E9%92%A2%E4%B9%8B%E7%82%BC%E9%87%91%E6%9C%AF%E5%B8%88&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&pn=90&rn=60&gsm=3c&1524867815458="
heads= {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
"referer":"https://image.baidu.com"
def get_download_url():
get_url_request = urllib.request.Request(pic_url,headers=heads)
get_url_response = urllib.request.urlopen(get_url_request,timeout=20)
get_url_context = get_url_response.read().decode("utf-8")
pic_url1 = re.findall("thumbURL:https", get_url_context, re.S)
count = 0
for i in range(len(pic_url)):
begin = get_url_context.find("thumbURL",count)
end = get_url_context.find("jpg",begin)
download_url = get_url_context[begin+11:end+3]
if download_url:
if not os.path.exists(path):
os.mkdir(path)
urllib.request.urlretrieve(download_url,path+str(i+1)+".png")
count = end
if __name__ == "__main__":
get_download_url()
本章节就结束到这里了~
本文主要介绍了Python自带的urllib的用法,并且也介绍bs如何使用,结合两个实战案例,基本上对这块的使用理解会更新~
下篇会介绍requests跟Scrapy,敬请期待~
最后再说点
本来之前规划很多东西,但是因为最近比较忙,进度非常慢,而且有点事情耽搁,python这块后面会随缘更新,了解到什么知识就写什么文章上去,主要涉及到测试、前端、python、git等等~
参考文献:
https://blog.csdn.net/qq_32166627/article/details/60882964
https://blog.csdn.net/xiligey1/article/details/73321152
感谢支持~