CRIME

导航

Python归纳 | 爬虫基础知识

1. urllib模块库

Urllib是python内置的HTTP请求库,urllib标准库一共包含以下子包:

urllib.error    由urllib.request引发的异常类
urllib.parse    URL解析组件
urllib.request    用于打开网址的可扩展库。
urllib.response    urllib使用的响应类。
urllib.robotparser    加载robots.txt文件并回答有关其他网址可抓取性的问题。

使用urllib库进行post操作,如何建立post数据格式?
1 将数据以字典形式建立
2 利用urllib.parse包的urlencode方法:

urlretrieve()函数

urlretrieve()将远程链接数据下载到本地
urlretrieve(url, filename=None, reporthook=None, data=None)
链接、保存本地路径、回调函数、post导服务器的数据

2. Beautiful Soup模块库

 Beautiful Soup是一个可以从HTML或XML文件中提取数据的第三方Python库,它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。

解析器 使用方法 优势 劣势
Python标准库 BeautifulSoup(markup, "html.parser") Python的内置标准库执行速度适中文档容错能力强 Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
lxml HTML 解析器 BeautifulSoup(markup, "lxml") 速度快文档容错能力强 需要安装C语言库
html5lib BeautifulSoup(markup, "html5lib") 最好的容错性以浏览器的方式解析文档生成HTML5格式的文档 速度慢不依赖外部扩展

2.1 创建Beautiful Soup对象

from bs4 import BeautifulSoup
#html为解析的页面获得html信息,为方便讲解,在此定义一个html文件
html = """
<html>
<head>
<title>CRIME</title>
</head>
<body>
<p class="title" name="blog"><b>My Blog</b></p>
<li><!--注释--></li>
<a href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" class="sister" id="link1">Html举例1</a><br/>
<a href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" class="sister" id="link2">Html举例1</a><br/>
<a href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" class="sister" id="link3">Html举例1</a><br/>
</body>
</html>

 创建Beautiful Soup对象

soup = BeautifulSoup(html,'lxml')

 还可以使用本地HTML文件来创建对象

soup = BeautifulSoup(open(test.html),'lxml')

 使用如下代码格式化输出

print(soup.prettify())

2.2 Beautiful Soup四大对象

 Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:

  • Tag
  • NavigableString
  • BeautifulSoup
  • Comment
(1) Tag

 Tag通俗点讲就是HTML中的一个个标签,例如

<title>CRIME</title>    # title就是HTML标签,标签加入里面包括的内容就是Tag

 用 Beautiful Soup 获取 Tags

print(soup.title)
#<title>CRIMEi</title>

print(soup.head)
#<head> <title>CRIME</title></head>

print(soup.a)
#<a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" class="sister" id="link1">Html举例1</a>

print(soup.p)
#<p class="title" name="blog"><b>My Blog</b></p>

 验证一下这些对象的类型:

print(type(soup.title))
#<class 'bs4.element.Tag'>

 Tag有两个重要的属性:name和attrs

name:
print(soup.name)
print(soup.title.name)
#[document]
#title

 soup 对象本身比较特殊,它的 name 即为 [document],对于其他内部标签,输出的值便为标签本身的名称。

attrs:
print(soup.a.attrs)
#{'class': ['sister'], 'href': 'http://xxxxx/xxxx/xxxx/xxxx/xxxx', 'id': 'link1'}

 把a 标签的所有属性打印输出,得到的类型是一个字典。
 如果想要单独获取某个属性,例如我们获取a标签的class叫什么,两个等价的方法如下:

print(soup.a['class'])
print(soup.a.get('class'))
#['sister']
#['sister']
(2) NavigableString

 得到了标签的内容,想要获取标签内部的文字,用 .string即可

print(soup.title.string)
#CRIME
(3) BeautifulSoup

 BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性:

print(type(soup.name))
print(soup.name)
print(soup.attrs)
#<class 'str'>
#[document]
#{}
(4) Comment

 Comment对象是一个特殊类型的NavigableString对象,其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦。

print(soup.li)
print(soup.li.string)
print(type(soup.li.string))
#<li><!--注释--></li>
#注释
#<class 'bs4.element.Comment'>

 li标签里的内容实际上是注释,但是如果我们利用 .string 来输出它的内容,我们发现它已经把注释符号去掉了,所以这可能会给我们带来不必要的麻烦。
 我们打印输出下它的类型,发现它是一个 Comment 类型,所以,我们在使用前最好做一下判断,判断代码如下:

from bs4 import element

if type(soup.li.string) == element.Comment:
     print(soup.li.string)

 上面的代码中,我们首先判断了它的类型,是否为 Comment 类型,然后再进行其他操作,如打印输出。

2.3 遍历文档数

(1) 直接子节点(不包含孙节点)
contents:

 tag的content属性可以将tag的子节点以列表的方式输出:

print(soup.body.contents)
#['\n', <p class="title" name="blog"><b>My Blog</b></p>, '\n', <li><!--注释--></li>, '\n', <a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" class="sister" id="link1">Html举例1</a>, <br/>, '\n', <a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" id="link2">Html举例2</a>, <br/>, '\n', <a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" id="link3">Html举例3</a>, <br/>, '\n']

 输出方式为列表,我们可以用列表索引来获取它的某一个元素:

print(soup.body.contents[1])
<p class="title" name="blog"><b>My Blog</b></p>
children:

 它返回的不是一个 list,不过我们可以通过遍历获取所有子节点,它是一个 list 生成器对象:

for child in soup.body.children:
     print(child)
(2) 搜索文档树(find()、find_all()函数)

 find_all方法返回文档中所有匹配对象的列表

find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)

 find方法返回第一个可匹配的对象,即find_all(...limit=1...)

find(name=None, attrs={}, recursive=True, text=None , **kwargs ) 

 find与find_all除了返回类型不一样,参数用法都一样,以下以find_all为例

name参数:

 name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉。

传递字符:

 最简单的过滤器是字符串,在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的<a>标签:

print(soup.find_all('a'))
#['\n', <p class="title" name="blog"><b>My Blog</b></p>, '\n', <li><!--注释--></li>, '\n', <a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" class="sister" id="link1">Html举例1</a>, <br/>, '\n', <a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" id="link2">Html举例2</a>, <br/>, '\n', <a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" id="link3">Html举例3</a>, <br/>, '\n']
传递正则表达式:

  如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容.下面例子中找出所有以b开头的标签,这表示和<b>标签都应该被找到

import re
for tag in soup.find_all(re.compile("^b")):
     print(tag.name)
#body
#b
#br
#br
#br
传递列表:

  如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回,下面代码找到文档中所有title标签和b标签:

print(soup.find_all(['title','b']))
#[<title>Jack_Cui</title>, <b>My Blog</b>]
传递True:

  True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点:

for tag in soup.find_all(True):
     print(tag.name)
#html
#head
...
#br
attrs参数:

  我们可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag。

print(soup.find_all(attrs={"class":"title"}))
#[<p class="title" name="blog"><b>My Blog</b></p>]
recursive参数:

  调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False。

text参数:

  通过 text 参数可以搜搜文档中的字符串内容,与 name 参数的可选值一样, text 参数接受字符串 , 正则表达式 , 列表, True。

 print(soup.find_all(text="Python3网络爬虫(三):urllib.error异常"))
#['Python3网络爬虫(三):urllib.error异常']
limit参数:

 find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果。
 文档树中有3个tag符合搜索条件,但结果只返回了2个,因为我们限制了返回数量:

 print(soup.find_all("a", limit=2))
#[<a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" id="link1">Html事例1</a>, <a class="sister" href="http://xxxxx/xxxx/xxxx/xxxx/xxxx" id="link2">Html事例2</a>]
attrs参数:

 如果传入 class 参数,Beautiful Soup 会搜索每个 class 属性为 title 的 tag 。kwargs 接收字符串,正则表达式

print(soup.find_all(class_="title"))
#[<p class="title" name="blog"><b>My Blog</b></p>]

Python爬虫入门实战

爬虫流程
  • 先由urllib的request打开Url得到网页html文档
  • 浏览器打开网页源代码分析元素节点
  • 通过Beautiful Soup或则正则表达式提取想要的数据
  • 存储数据到本地磁盘或数据库(抓取,分析,存储)

练习一:对豆瓣的一个电影排名URL进行抓取

from urllib import request                #导入urillib中的request模块
from bs4 import BeautifulSoup        #导入bs4中的BeautifulSoup模块

##构造头文件,模拟浏览器访问
url="https://movie.douban.com/chart"
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
page = request.Request(url,headers=headers)              #用urllib的request打开Url得到网页html文档
page_info = request.urlopen(page).read().decode('utf-8')   #打开Url,获取HttpResponse返回对象并读取其ResposneBody
soup = BeautifulSoup(page_info, 'html.parser')   # 将获取到的内容转换成BeautifulSoup格式,并将html.parser作为解析器

titles = soup.find('div','indent')   # 查找所有div标签中class='indent'的Tag
for t in titles.find_all('a',class_="nbg"):     # 查找所有a标签中class=nbg的Tag(隐藏的class属性不解!!!!)
    print(t.attrs['title'])            # 打印查找到的每一个a标签中的title
    print(t.attrs['href'])            #打印查找到的每一个a标签中的文章链接href
                      
#在磁盘以只写的方式打开/创建一个名为 articles 的txt文件
#open()是读写文件的函数,with语句会自动close()已打开文件
with open(r"D:\BaiduYunDownload\articles.txt","w") as file:       
    for t in titles.find_all('a',class_="nbg"): 
        file.write(t.attrs['title']+'\n') 
        file.write(t.get('href')+'\n\n')    

练习二:爬取169图片并保存到本地

from urllib import request              #导入urillib中的request模块
from  bs4 import BeautifulSoup     #导入bs4中的BeautifulSoup模块
import re
import time

def getImg(url):
    ##构造头文件,模拟浏览器访问
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
    page = request.Request(url,headers=headers)
     #用request打开Url,获取HttpResponse返回对象并读取其ResposneBody
    html=request.urlopen(page).read().decode('utf-8','ignore') 
     #将获取到的内容转换成BeautifulSoup格式,并将html.parser作为解析器
    soup = BeautifulSoup(html, 'html.parser')  

    links=soup.find('div',class_='big_img')     #获取标签为div,class属性为big_img的对象
    for link in links.find_all('img',src=re.compile(r'.jpg$')):    #获取标签为img,无class属性,以.jpg结尾的src属性列表并迭代对象
        path = r'D:\BaiduYunDownload\IMG'  
        request.urlretrieve(link.attrs['src'],path+'\%s.jpg' % time.time())    #使用request.urlretrieve()直接将所有远程链接数据下载到本地,link.attr返回的是一个属性字典     

if __name__=="__main__":
    url=input("请输入网址:")
    n=int(input("请输入页数:"))
    getImg(url)
    for i in range(2,n+1):
        url2=url[0:47]+"_"+str(i)+".html"
        getImg(url2)

3. Requests模块库

4. lxml库XPath模块

Python爬虫入门实战

import requests
from lxml import etree
import re

url=str(input('请输入网址:'))
file_name=str(input('请输入文件夹名:'))

headers = { "User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" }    
count=0
flag=1
while flag:
    req =requests.get(url,headers=headers).content 
    html=etree.HTML(req)
    element =html.xpath('//p/img/@src')
    for i in element:
        r = requests.get(i)
        count=count+1
        print('下载第{}张'.format(count))
        with open("D:/BaiduYunDownload/IMG/"+str(file_name)+str(count)+".jpg", "wb") as f:
            f.write(r.content)
        
    judge=html.xpath('//ul[@class="pagelist"]/li[last()]/@class')
    if judge==['thisclass']:
        flag=0
    
    urls=html.xpath('//div/ul[@class="pagelist"]/li[last()]/a/@href')[0]
    url=url[:46]+urls

    print("完成")

posted on 2019-04-29 15:27  CRIME  阅读(293)  评论(0)    收藏  举报