python爬虫入门

521 阅读6分钟

爬虫能干什么呢?一句话概括,正常通过浏览器可以获取的数据,爬虫都可以获取。这句话可以说是包罗万象。一是说明了爬虫的本质是一个服务端,实现的功能类似于浏览器;二是说明了爬虫的界限,如果不能正常访问到的数据就不能通过爬虫获取;三是爬虫的最高境界,只要是浏览器能正常访问的都可以用爬虫获取。

爬虫:我们需要干的事情其实就两件事情:找到我们需要的网页,然后把他们一个一个处理一遍。一,怎么找到我们需要的网页的那个入口?二,怎么处理我们需要处理的网页?

爬虫的核心模块有三个:请求、解析、储存。

  1. 请求

我们先使用requests包。这是一个第三方模块,对HTTP协议进行了高度封装,非常好用。HTTP协议:简单地说就是一个请求过程。服务器响应并返回相应数据,我们要实现的目的是把网页请求(或者说下载)下来。

安装requests

pip install requests

导入requests

import requests

调用requests的get函数,把网页请求下来

r = requests.get('www.baidu.com')

输出请求下来的网页格式

print(r.text)

requests的一些属性

>>> import requests
>>> r = requests.get("http://www.baidu.com")
>>> r.status_code
200
>>> r.endcoding = 'utf-8'
>>> r.text

requests异常问题

requests的一些方法

一些小实例

# 实例1:
import requests
url = "https://item.jd.com/1350837.html"
try:
     r = requests.get(url)
     r.raise_for_status()
     r.encoding = r.apparent_encoding
     print(r.text[:1000])
 except:
     print("爬取失败")

#实例2 搜索引擎关键字搜索
import requests
r = requests.get(url='http://www.itwhy.org')    # 最基本的GET请求
print(r.status_code)    # 获取返回状态
r = requests.get(url='http://dict.baidu.com/s', params={'wd':'python'})   #带参数的GET请求
                                                             #params为url中的额外参数,字典或字节流格式
print(r.url)
print(r.text)   #打印解码后的返回数据

#ip地址查询
#www.ip138.com
import requests
url = "http://m.ip138.com/ip.asp?ip="
try:
    r = requests.get(url+'210.40.17.226')
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.text[-500:])
except:
    print("爬取失败")
#用来页面验证、人机交互
  1. 解析

requests包可以使用http协议获取相应的网页文件,但是往往请求下来的是整个页面的代码,这样的信息太多了,从这一大坨代码里面找信息太麻烦了。我们需要另一个库来解析文件:BeautifulSoup4(bs4)

bs4安装:

pip install beautifulsoup4

bs4是一个非常好的解析网页的库。这次的解析先给大家看bs4里面最常用的几个BeautifulSoup对象的方。我们使用的这几个方法,主要是通过HTML的标签和标签里面的参数来定位,然后用特定方法提取数据。

beautifulsoup的简单使用:

form bs4 import  BeautifulSoup 
......
soup = BeautifulSoup(html,'html.parser')    #html.parser是解析器

#还有 lxml的html   lxml的xml  html5lib  解析器
#<p>data</P>可以替换成其他的html属性

测试链接:python123.io/ws/demo.htm…

点击进入

测试这个网页:

import requests
r = requests.get('https://python123.io/ws/demo.html')
print(r.text)

返回信息:

<html>
<head>
<title>This is a python demo page
</title>
</head>
<body>
<p class="title"><b>The demo python introduces several python courses.</b></p>
<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:      
<a href="http://www.icourse163.org/course/BIT-268001" class="py1" id="link1">Basic Python</a> and <a href="http://www.icourse163.org/course/BIT-1001870001" class="py2" id="link2">Advanced Python</a>.</p>
</body>
</html>

开始解析:

import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
#soup2 = BeautifulSoup(open("D://demo.html"),"html.parser")
print(soup.prettify())

理解:

#html文件的大概框架
<html>
    <body>
        <div class="abc"></div>
        <p class="bcd"></p> #标签格式<p></p> 此处标签name就是p,class="bcd"是属性域,键值对构成
    </body>
b</html>

#BeautifulSoup是解析、遍历、维护、“标签书”的功能库

BeautifulSoup类的基本元素

1.Tag:标签。最基本的信息组织单元,<>、</>开头和结尾

2.Name:标签的名字,格式:< tag>.name

3.Attributes:标签的属性,字典形式组织,格式< tag>.attrs

4.NavigableString:标签内的非属性字符串,格式< tag>.string

5.Comment:标签内字符串的注释部分,一种特殊的Comment类型

解析1:

import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
print(soup.prettify())
print("-------------------------------")
print(soup.title)
print("-------------------------------")
print(soup.a)
print("-------------------------------")
print(soup.a.name)
print("-------------------------------")
print(soup.a.parent.name)
print("-------------------------------")
print(soup.a.parent.parent.name)

解析2:

import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
tag = soup.a
print("-------------------------------")
print(tag.attrs)
print("-------------------------------")
print(tag.attrs['class'])
print("-------------------------------")
print(tag.string)
print("-------------------------------")
print(soup.p.string)

解析3:

3种遍历方式:

1.下行遍历:

    .contents:子节点的列表,将< tag>所有的儿子节点存入列表
    .childen:子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
    .desendants:子孙节点的迭代类型,包括所有的子孙节点,用于循环遍历
import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
print("-------------------------------")
print(soup.head)
print("-------------------------------")
print(soup.head.contents)
print("-------------------------------")
print(soup.body.contents)
print("-------------------------------")
print(len(soup.body.contents))      #获得body儿子节点的数量(个数)
print("-------------------------------")
print(soup.body.contents[1])         #因为存放的方式为列表,可以用列表下表的方式获取
print("-------------------------------")
for child in soup.body.children:          #遍历儿子节点
    print(child)
    print("--")

2.上行遍历:

.parent:节点的父亲标签
.parents:节点先辈标签的迭代类型,用于循环遍历先辈节点
import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
print("-------------------------------")
print(soup.head)
print("-------------------------------")
print(soup.head.parent)
print("-------------------------------")
for parent in soup.a.parents:   #上行遍历
    if parent is None:
        print(parent)
    else:
        print(parent.name)

3.平行遍历:

.next_sibling:返回下一个平行节点
.previous_sibling:返回上一个平行节点
.next_siblings:返回后续的所有平行节点
.previous_siblings:返回前序的所有平行节点

实战小项目:

#爬取中国大学排名
import requests
from bs4 import BeautifulSoup
import bs4
 
def getHTMLText(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""
 
def fillUnivList(ulist, html):
    soup = BeautifulSoup(html, "html.parser")
    for tr in soup.find('tbody').children:
        if isinstance(tr, bs4.element.Tag):
            tds = tr('td')
            ulist.append([tds[0].string, tds[1].string, tds[3].string])
 
def printUnivList(ulist, num):
    print("{:^10}\t{:^6}\t{:^10}".format("排名","学校名称","总分"))
    for i in range(num):
        u=ulist[i]
        print("{:^10}\t{:^6}\t{:^10}".format(u[0],u[1],u[2]))
     
def main():
    uinfo = []
    url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
    html = getHTMLText(url)
    fillUnivList(uinfo, html)
    printUnivList(uinfo, 100) # 100 univs
main()
#一周天气
import csv
import urllib.request
from  bs4 import BeautifulSoup
 
url = "http://www.weather.com.cn/weather/101270101.shtml"
header = ("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36")  # 设置头部信息
opener = urllib.request.build_opener()  # 修改头部信息
opener.addheaders = [header]         #修改头部信息
request = urllib.request.Request(url)   # 制作请求
response = urllib.request.urlopen(request)   #  得到请求的应答包
html = response.read()   #将应答包里面的内容读取出来
html = html.decode('utf-8')    # 使用utf-8进行编码,不重新编码就会成乱码
 
 
final = []   #初始化一个空的list,我们为将最终的的数据保存到list
bs = BeautifulSoup(html,"html.parser")   # 创建BeautifulSoup对象
body = bs.body  # 获取body部分
data = body.find('div',{'id':'7d'})  # 找到id为7d的div
ul = data.find('ul')  # 获取ul部分
li = ul.find_all('li')  # 获取所有的li
# print (li)
 
i = 0
for day in li:  # 对每个li标签中的内容进行遍历
    if i < 7:
        temp = []
        date = day.find('h1').string # 找到日期
#         print (date)
        temp.append(date)  # 添加到temp中
    #     print (temp)
        inf = day.find_all('p')  # 找到li中的所有p标签
    #     print(inf)
    #     print (inf[0])
        temp.append(inf[0].string)  # 第一个p标签中的内容(天气状况)加到temp中
        if inf[1].find('span') is None:
            temperature_highest = None # 天气预报可能没有当天的最高气温(到了傍晚,就是这样),需要加个判断语句,来输出最低气温
        else:
            temperature_highest = inf[1].find('span').string # 找到最高温度
            temperature_highest = temperature_highest.replace('℃', '') # 到了晚上网站会变,最高温度后面也有个℃
        temperature_lowest = inf[1].find('i').string  #找到最低温度
        temperature_lowest = temperature_lowest.replace('℃', '')  # # 最低温度后面有个℃,去掉这个符号
        temp.append(temperature_highest)
        temp.append(temperature_lowest)
        final.append(temp)
        i = i +1
        
# print(final)
 
with open('weather.csv', 'a', errors='ignore', newline='') as f:
            f_csv = csv.writer(f)
            f_csv.writerows(final)