点我

概述

概述

网络爬虫是一种按照一定规则,自动地抓取万维网信息的程序或者脚本

网页中有很多信息和数据,要想从网页中抓取信息和数据,并保存到本地,这就是网络爬虫

网页一般是由HTML语言编写,要想从网页中抓取内容,其实就是在HTML中,找到相应的内容进行提取

网页

大部分的网页由三部分组成

HTML -- 超文本标记语言

整个网页的结构,类似于人的骨架,定义了你的眼睛、鼻子为位置在哪里

CSS -- 层叠样式表

CSS表示样式,定义了外观

JavaScript -- 脚本语言

JavaScript表示功能,网页中的交互内容,交互特效都包含在其中

HTML网页结构

img

网络请求

当用户浏览器向目标服务器发送请求的过程,称之为网络请求

常见的网络请求方式主要分为以下8种:

请求方式描述
GET发送请求来获得服务器上的资源,但请求的内容会以明文的方式显示在URL栏中
POST向服务器提交资源让服务器处理
HEAD主要用来检查资源或超链接的有效性或是否可以可达、检查网页是否被篡改或更新
PUT向指定资源位置中上传其更新内容
DELETE请求服务器删除某资源
CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器
OPTIONS允许客户端查看服务器的性能
TRACE回显服务器收到的请求,主要用于测试或诊断

请求头常见参数

User-Agent

浏览器的名称

向服务器发送请求时,服务器通过该参数了解请求是从何种浏览器发出,以便返回正确的信息

referer:表明用户是从哪个网站跳转而来

cookie:HTTP协议是无状态的,cookie用于标识用户的身份信息

常见响应状态码

1xx -- 消息响应

表示临时响应并需要请求者继续执行操作的状态码

100(继续) 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分
101(切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换

2xx -- 成功响应

表示成功处理了请求的状态码

200(成功) 服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。如果是对您的 robots.txt 文件显示此状态码,则表示 Googlebot 已成功检索到该文件

201(已创建) 请求成功并且服务器创建了新的资源

202(已接受) 服务器已接受请求,但尚未处理

203(非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源

204(无内容) 服务器成功处理了请求,但没有返回任何内容

205(重置内容) 服务器成功处理了请求,但没有返回任何内容。与 204 响应不同,此响应要求请求者重置文档视图(例如,清除表单内容以输入新内容)

206(部分内容) 服务器成功处理了部分 GET 请求

3xx -- 重定向响应

要完成请求,需要进一步操作。通常,这些状态码用来重定向

300(多种选择) 针对请求,服务器可执行多种操作。服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择

301(永久移动) 请求的网页已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。您应使用此代码告诉 Googlebot 某个网页或网站已永久移动到新位置

4xx -- 客户端错误

这些状态码表示请求可能出错,妨碍了服务器的处理

400(错误请求) 服务器不理解请求的语法

401(未授权) 请求要求身份验证。对于登录后请求的网页,服务器可能返回此响应

403(禁止) 服务器拒绝请求

404(未找到) 服务器找不到请求的网页。例如,对于服务器上不存在的网页经常会返回此代码

5xx -- 服务器端错误

这些状态码表示服务器在处理请求时发生内部错误

500(服务器内部错误) 服务器遇到错误,无法完成请求

501(尚未实施) 服务器不具备完成请求的功能。例如,服务器无法识别请求方法时可能会返回此代码

502(错误网关) 服务器作为网关或代理,从上游服务器收到无效响应

503(服务不可用) 服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态

504(网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求

505(HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本

URL

概述

URL是uniform Resource Locator的缩写,中文全称:统一资源定位符

每一个信息资源在网上都有唯一的一个地址,这就是URL

URL的组成

格式:

协议://用户名:密码@子域名.域名.顶级域名:端口号/目录/文件名.文件后缀?参数=值#锚部分

实例:

http://www.godsince.com:8080/news/index.asp?boardID=5&ID=24618&page=1#r_70732412

img

协议:模式/协议(scheme),在Internet中可使用多种协议,如HTTP,FTP等。在”HTTP”后面的“//”为分隔符

域名:也可使用IP地址作为域名使用。

端口:不是一个URL必须的部分,如果省略端口部分,将采用默认端口。

虚拟目录:从域名后的第一个“/”开始到最后一个“/”为止。虚拟目录不是一个URL必须的部分。

文件名:从域名后的最后一个“/”至“?”(或“#”或至结束)为止,是文件名部分。件名部分不是一个URL必须的部分,如果省略该部分,则使用默认的文件名。

参数:从“?”开始到“#”(或至结束)为止之间的部分为参数部分,又称搜索部分、查询部分。参数间用 “&”作为分隔符。

锚:或称片段(fragment),HTTP请求不包括锚部分,从“#”开始到最后,都是锚部分。

本例中的锚部分是 “r_70732423“。锚部分不是一个URL必须的部分。

锚点作用:打开用户页面时滚动到该锚点位置

三种提取数据方法

从HTML页面中提取所需的信息,一般有三种方法:Xpath语法、bs4库和正则表达式

三种方法对比

img

网络请求

网络爬虫基本流程

1、得到HTML页面,即发出网络请求

2、按照一定的规则进行数据的提取

3、数据的存储

HTTP请求

模拟http请求的过程是极其复杂的,用户需要向DNS发送一个请求以获取IP,再将获取后的IP发送给服务器,服务器返回HTML。

其实这个过程可以python代为完成,一般来讲,python有两个基础库来完成模拟请求:urllib 与 requests

注意:requests库并不是内置库,需要额外安装【安装命令:pip install requests】

示例

代码部分:

"""
@time:2022-03-30
@desc:
    使用python实现豆瓣账号模拟登陆功能
"""
import requests


# 登陆的URL
url = "https://accounts.douban.com/passport/login"


# 伪装user-agent
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/100.0.4896.60 Safari/537.36 "
}


# 账号信息
data = {
    "name": "1666197054@qq.com",
    "password": "douban.com459.."
}


# 模拟登陆
session = requests.session()
session.post(url, data, headers)

response = session.get(url="https://movie.douban.com",headers=headers)
status_code = response.status_code
print(status_code)

结果输出:

img

XPath

概述

XPath(XML Path Language)是一门在XML和HTML文档中查找信息的语言,可用来在XML和HTML文档中对元素和属性进行遍历

简单来讲,我们要提取的数据为超文本数据,想要获取超文本数据里面的内容,就要按照一定规则来进行数据的获取,这种规则叫做Xpath语法

XPath用于在HTML文档中通过元素【HTML标签】和属性【HTML标签的属性】进行数据的定位

语法

1.节点选取

表达式描述示例说明
nodename选取此节点的所有子节点div选取div标签下的所有标签
//从全局节点中选择节点,任意位置均可//div选取整个HTML页面中的所有div标签
/选取某个节点下的节点//head/title选取head标签下的的title标签
@选取带某个属性的节点//div[@id]选取带有id属性的div标签
.当前节点下./span选取当前节点下的span标签

2.谓语

表达式描述
//head/meta[1]//head/meta[k]选取所有head标签下的第一个meta标签选取所有head标签下的第k个meta标签
//head/meta[last()]选取所有head标签下的最后一个meta标签
//head/meta[position() < 3]选取所有head标签下的前两个meta标签
//div[@id]选取所有带有id属性的div标签
//div[@id='u1']选取所有拥有id='u1' 属性的div标签

3.通配符

通配符描述示例说明
*匹配任意节点//div[@id='u1']/*选取所有拥有id='u1'属性的div标签下的所有节点
@*匹配节点中的任何属性//meta[@*]选取所有拥有属性的meta标签

4.选取多个路径

符号描述示例说明
\ 选择多个路径//meta \//title选择所有的meta和title标签

lxml库

工作流程

发送网络请求 --> 获取HTML --> Xpath语法 --> 获取数据

注意:XPath语法无法直接作用于字符串进行数据提取

网页中的HTML可以用XPath语法获取数据,但无法在字符串中提取

lxml作用

将html字符串进行解析,供xpath语法进行数据提取

示例

简单取值

"""
@time:2022-03-31
@desc:

"""
from lxml import etree

# 读取txt文档
txt = \
"""
<tr class = "hosts">
    <td class = '1', id = 'even' >host1</td>
    <td class = '2', id = 'even' >host2</td>
    <td class = '3' >host3</td>
    <td class = '4' >hos4</td>
    <td class = '5' >host5</td>
    <td class = '6' >爬虫</td>
</tr>
"""


# 将txt字符串转换为html
html = etree.HTML(txt)


# 先对其进行编码再进行解码,就变成了字符串
# result = etree.tostring(html,encoding='utf8').decode('utf8')


# 1.获取所有的td标签
tds = html.xpath("//td")
for td in tds:
    t = etree.tostring(td, encoding='utf8').decode('utf8')
    # print(t)


# 2.获取第一个td标签
td1 = html.xpath('//td[1]')[0]
# print(etree.tostring(td1, encoding='utf8').decode('utf8'))


# 3.获取最后一个td标签
td_last = html.xpath('//td[last()]')[0]
# print(etree.tostring(td_last,encoding='utf8').decode('utf8'))


# 4.获取所有id='even'属性的标签
td_id = html.xpath("//td[@id='even']")
for id in td_id:
    evens = etree.tostring(id, encoding="utf8").decode("utf8")
    # print(evens)


# 5.获取标签中class属性值
class_value = html.xpath("//@class")
# print(class_value)

获取豆瓣TOP50 影评

"""
@time:2022-03-31
@desc:
    爬取豆瓣TOP50影评
"""
import requests
from lxml import etree

# 获取影评信息
def info(url):
    response = requests.get(url, headers=headers)
    content = response.content.decode('utf-8')
    html = etree.HTML(content)
    # 电影名
    move = html.xpath('//div[@class="subject-title"]/a/text()')[0][2:]
    # 评论者
    commentator = html.xpath('//header[@class="main-hd"]//span/text()')[0]
    # 评分
    scores = html.xpath('//span/@title')
    if scores:
        score = scores[0]
    else:
        score = "无评分"

    # 评论
    comment = html.xpath('//div[@id="link-report"]//p/text()')[0]

    move_info = {
        "电影名:": move,
        "评论者:": commentator,
        "评分:": score,
        "评论:": comment
    }
    moves.append(move_info)





# 获取所有影评url链接
def urls():
    for i in range(5):
        url = "https://movie.douban.com/review/best/?start={}".format(i * 20)
        response = requests.get(url, headers=headers)
        content = response.content.decode('utf-8')

        html = etree.HTML(content)
        move_url = html.xpath('//h2/a/@href')
        for url in move_url:
            move_urls.append(url)


if __name__ == '__main__':
    move_urls = []
    moves = []
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/100.0.4896.60 Safari/537.36 "
    }
    urls()
    for url in move_urls:
        info(url)

    print("当前共{}条影评".format(len(moves)))
    for move in moves:
        for key,value in move.items():
            print(key + ":" + value)
        print("*" * 100)

微博热搜

"""
@time:2022-03-31
@desc:
    爬取微博热搜榜
"""
import requests
from lxml import etree

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/100.0.4896.60 Safari/537.36 "
}

url = "https://s.weibo.com/top/summary"
response = requests.get(url, headers=headers)
content = response.content.decode('utf-8')

html = etree.HTML(content)
titles = html.xpath('//td[@class="td-02"]/a/text()')
for title in titles:
    print(title)

百度热搜

"""
@time:2022-03-31
@desc:
    爬取百度热搜榜单
"""
import requests
from lxml import etree

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/100.0.4896.60 Safari/537.36 "
}

url = "https://top.baidu.com/board?tab=realtime"
response = requests.get(url, headers=headers)
content = response.content.decode('utf-8')

html = etree.HTML(content)
title = html.xpath('//div[@class="category-wrap_iQLoo horizontal_1eKyQ"]//div[@class="c-single-text-ellipsis"]//text()')
index = html.xpath('//div[@class="category-wrap_iQLoo horizontal_1eKyQ"]//div[@class="hot-index_1Bl1a"]//text()')

for i in range(len(index)):
    print("{},热搜指数:{}".format(title[i][2:],index[i][2:]))

结果输出:

img

BeautifulSoup

概述

和lxml一样, BeautifulSoup 也是一个HTML/XML的解析器,主要功能为解析和提取HTML/XML数据

简单来讲, BeautifulSoup只是一个从HTML字符串中提取数据的工具

BeautifulSoup与lxml的区别

lxml只会局部遍历,BeautifulSoup是基于HTML DOM树的,会加载整个文档,解析DOM树

因此所需的时间和内存开销都会很大,所以性能要低于lxml

练习基础语法

"""
@time:2022-03-31
@desc:
    练习bs4语法
"""
text = \
"""
<ul class="ullist" padding="1" spacing="1">
    <li>
        <div id="top">
            <span class="position" width="350">职位名称</span>
            <span>职位类别</span>
            <span>人数</span>
            <span>地点</span>
            <span>发布时间</span>
        </div>
        <div id="even">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=33824&amp;keywords=python&amp;tid=87&amp;lid=2218">python开发工程师</a>
            </span>
            <span class="position" width="350">技术类</span>
            <span>2</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="odd">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=29938&amp;keywords=python&amp;tid=87&amp;lid=2218">python后端</a>
            </span>
            <span>技术类</span>
            <span>2</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="even">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=31236&amp;keywords=python&amp;tid=87&amp;lid=2218">高级Python开发工程师</a>
            </span>
            <span>技术类</span>
            <span>2</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="odd">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=31235&amp;keywords=python&amp;tid=87&amp;lid=2218">python架构师</a>
            </span>
            <span>技术类</span>
            <span>1</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="even">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=34531&amp;keywords=python&amp;tid=87&amp;lid=2218">Python数据开发工程师</a>
            </span>
            <span>技术类</span>
            <span>1</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="odd">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=34532&amp;keywords=python&amp;tid=87&amp;lid=2218">高级图像算法研发工程师</a>
            </span>
            <span>技术类</span>
            <span>1</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="even">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=31648&amp;keywords=python&amp;tid=87&amp;lid=2218">高级AI开发工程师</a>
            </span>
            <span>技术类</span>
            <span>4</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="odd">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=32218&amp;keywords=python&amp;tid=87&amp;lid=2218">后台开发工程师</a>
            </span>
            <span>技术类</span>
            <span>1</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="even">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=32217&amp;keywords=python&amp;tid=87&amp;lid=2218">Python开发(自动化运维方向)</a>
            </span>
            <span>技术类</span>
            <span>1</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
        <div id="odd">
            <span class="l square">
              <a target="_blank" href="position_detail.php?id=34511&amp;keywords=python&amp;tid=87&amp;lid=2218">Python数据挖掘讲师 </a>
            </span>
            <span>技术类</span>
            <span>1</span>
            <span>上海</span>
            <span>2018-10-23</span>
        </div>
    </li>
</ul>
"""


# 导入模块
from bs4 import BeautifulSoup


# 实例化BeautifulSoup对象
# BeautifulSoup(对象,解释器类型)
soup = BeautifulSoup(text,'lxml')


""" 
1.获取所有的div标签,find_all()
返回的同样是列表

divs = soup.find_all('div')
print(type(divs))
for div in divs:
    print(div, '\n', '*'*50, end='\n')
"""


"""
2.获取第2个div标签

div_1 = soup.find_all('div')[1]
print(div_1)
"""

"""
3.获取从第二个到第十个的div标签

div_2_10 = soup.find_all('div')[1:10]
for div in div_2_10:
    print(div, '\n', '*'*50, end='\n')
"""

"""
4.获取拥有指定属性的标签(id=even的div标签)

# 方法1
divs_id = soup.find_all("div", id="even")
for div in divs_id:
    print(div, '\n', '*'*50, end='\n')

# 方法2,以字典形式
divs_id = soup.find_all('div', attrs={"id": "even"})
for div in divs_id:
    print(div, '\n', '*'*50, end='\n')
"""

"""
5.获取拥有多个属性的标签(class=position,width=350的div标签)
当属性名与关键词冲突时,需要在属性名后加_

# 方法1:
spans = soup.find_all('span', class_='position', width='350')
for div in spans:
    print(div, '\n', '*'*50, end='\n')

# 方法2
spans = soup.find_all('span', attrs={"class": "position", "width": "350"})
for div in spans:
    print(div, '\n', '*'*50, end='\n')
"""

"""
6.获取属性值(a标签中的href值)

# 方法1,,通过下标方式提取
a_s = soup.find_all('a')
for a in a_s:
    href = a['href']
    print(href)

# 方法2,利用attr参数提取
a_s = soup.find_all('a')
for a in a_s:
    href = a.attrs['href']
    print(href)
"""

"""
7.获取所有的职位信息

# 方法1
infos = []
divs = soup.find_all("div")[1:]
for div in divs:
    # .string 获取标签下的的全部文本信息
    # 职业
    profession = div.find_all('a')[0].string
    # 类别
    position = div.find_all('span')[1].string
    # 人数
    numbers = div.find_all('span')[2].string
    # 地区
    area = div.find_all('span')[3].string
    # 时间
    time = div.find_all('span')[4].string
    positions = {
        "职业": profession,
        "类别": position,
        "人数": numbers,
        "地区": area,
        "时间":time
    }
    infos.append(positions)

for info in infos:
    for key,value in list(info.items()):
        print(key + ":" + value)
    print("*" * 30)



# 方法2
divs = soup.find_all('div')[1:]
for div in divs:
    # stripped_strings 去除掉换行符,空格等无意义字符
    # .string获取标签下的全部文本信息
    infos = list(div.stripped_strings)
    print(infos)
"""

示例

工作流程

  • 导入模块
  • 定义url和请求头参数
  • requests发送HTML请求,获取HTML字符串
  • 实例化BeautifulSoup对象(中介)
  • 获取数据
  • 存储数据

微博热搜

"""
@time:2022-03-31
@desc:
    爬取新浪微博搜
"""
from bs4 import BeautifulSoup
import requests

sinas = []
url = "https://s.weibo.com/top/summary?display=0&retcode=6102"

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/100.0.4896.60 Safari/537.36 "
}

# 发起网络请求
response = requests.get(url, headers=headers)
content = response.content.decode('utf-8')

# 实例化beautifulsoup对象
soup = BeautifulSoup(content, 'lxml')
tds = soup.find_all('td', attrs={"class": "td-02"})
for td in tds:
    event = td.find_all('a')[0].string
    hot = td.find_all('span')[0].string
    sina = {
        "title:": event,
        "hot:": hot
    }
    sinas.append(sina)
print(sinas)

百度热搜

"""
@time:2022-03-31
@desc:
    百度热搜
"""
from bs4 import BeautifulSoup
import requests

url = "https://top.baidu.com/board?tab=realtime"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/100.0.4896.60 Safari/537.36 "
}


# 发起网络请求
response = requests.get(url,headers=headers)
content = response.content.decode('utf-8')

# 实例化beautifulsoup对象
soup = BeautifulSoup(content, 'lxml')

# 获取数据
divs = soup.find_all('div', attrs={"class": "c-single-text-ellipsis"})
hots = soup.find_all('div', class_="hot-index_1Bl1a")

# 显示数据
for i in range(len(list(divs))):
    print("{},热度:{}".format(divs[i].string[2:],hots[i].string[2:]))

结果输出:

img

分类: Python

评论

-- 评论已关闭 --

目录