python 爬虫初探 一

2018.05.29*****************************************************************************
author:wills

网络爬虫和相关工具

1. 网络爬虫

网络爬虫(web crawler),以前经常称之为网络蜘蛛(spider),是按照一定的规则自动浏览万维网并获取信息的机器人程序(或脚本),曾经被广泛的应用于互联网搜索引擎。使用过互联网和浏览器的人都知道,网页中除了供用户阅读的文字信息之外,还包含一些超链接。网络爬虫系统正是通过网页中的超链接信息不断获得网络上的其它页面。正因如此,网络数据采集的过程就像一个爬虫或者蜘蛛在网络上漫游,所以才被形象的称为网络爬虫或者网络蜘蛛。

1.1 爬虫的应用领域

在理想的状态下,所有ICP(Internet Content Provider)都应该为自己的网站提供API接口来共享它们允许其他程序获取的数据,在这种情况下爬虫就不是必需品,国内比较有名的电商平台(如淘宝、京东等)、社交平台(如腾讯微博等)等网站都提供了自己的Open API,但是这类Open API通常会对可以抓取的数据以及抓取数据的频率进行限制。对于大多数的公司而言,及时的获取行业相关数据是企业生存的重要环节之一,然而大部分企业在行业数据方面的匮乏是其与生俱来的短板,合理的利用爬虫来获取数据并从中提取出有价值的信息是至关重要的。当然爬虫还有很多重要的应用领域,以下列举了其中的一部分:

1.1.1. 搜索引擎
1.1.2. 新闻聚合
1.1.3. 社交应用
1.1.4. 舆情监控
1.1.5. 行业数据

2. 合法性和背景调研

2.1 爬虫合法性探讨

2.1.1. 网络爬虫领域目前还属于拓荒阶段,虽然互联网世界已经通过自己的游戏规则建立起一定的道德规范(Robots协议,全称是“网络爬虫排除标准”),但法律部分还在建立和完善中,也就是说,现在这个领域暂时还是灰色地带。
2.1.2. “法不禁止即为许可”,如果爬虫就像浏览器一样获取的是前端显示的数据(网页上的公开信息)而不是网站后台的私密敏感信息,就不太担心法律法规的约束,因为目前大数据产业链的发展速度远远超过了法律的完善程度。
2.1.3. 在爬取网站的时候,需要限制自己的爬虫遵守Robots协议,同时控制网络爬虫程序的抓取数据的速度;在使用数据的时候,必须要尊重网站的知识产权(从Web 2.0时代开始,虽然Web上的数据很多都是由用户提供的,但是网站平台是投入了运营成本的,当用户在注册和发布内容时,平台通常就已经获得了对数据的所有权、使用权和分发权)。如果违反了这些规定,在打官司的时候败诉几率相当高。

2.2 Robots.txt文件

大多数网站都会定义robots.txt文件,下面以淘宝的robots.txt文件为例,看看该网站对爬虫有哪些限制。

User-agent:  Baiduspider
Allow:  /article
Allow:  /oshtml
Disallow:  /product/
Disallow:  /

User-Agent:  Googlebot
Allow:  /article
Allow:  /oshtml
Allow:  /product
Allow:  /spu
Allow:  /dianpu
Allow:  /oversea
Allow:  /list
Disallow:  /

User-agent:  Bingbot
Allow:  /article
Allow:  /oshtml
Allow:  /product
Allow:  /spu
Allow:  /dianpu
Allow:  /oversea
Allow:  /list
Disallow:  /

User-Agent:  360Spider
Allow:  /article
Allow:  /oshtml
Disallow:  /

User-Agent:  Yisouspider
Allow:  /article
Allow:  /oshtml
Disallow:  /

User-Agent:  Sogouspider Allow:  /article Allow:  /oshtml Allow:  /product Disallow:  / User-Agent:  Yahoo! Slurp Allow:  /product Allow:  /spu Allow:  /dianpu Allow:  /oversea Allow:  /list Disallow:  / User-Agent:  * Disallow:  /

注意上面robots.txt第一段的最后一行,通过设置“Disallow: /”禁止百度爬虫访问除了“Allow”规定页面外的其他所有页面。因此当你在百度搜索“淘宝”的时候,搜索结果下方会出现:“由于该网站的robots.txt文件存在限制指令(限制搜索引擎抓取),系统无法提供该页面的内容描述”。百度作为一个搜索引擎,至少在表面上遵守了淘宝网的robots.txt协议,所以用户不能从百度上搜索到淘宝内部的产品信息。

3. 相关工具介绍

3.1 HTTP协议

在开始讲解爬虫之前,我们稍微对HTTP(超文本传输协议)做一些回顾,因为我们在网页上看到的内容通常是浏览器执行HTML语言得到的结果,而HTTP就是传输HTML数据的协议。HTTP是构建于TCP(传输控制协议)之上应用级协议,它利用了TCP提供的可靠的传输服务实现了Web应用中的数据交换。按照维基百科上的介绍,设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法,也就是说这个协议是浏览器和Web服务器之间传输的数据的载体。关于这个协议的详细信息以及目前的发展状况,大家可以阅读阮一峰老师的《HTTP 协议入门》《互联网协议入门》系列以及《图解HTTPS协议》进行了解,还可以访问《编程学习-HTTP-超文本传输协议》进行迅速了解

3.2 相关工具

3.2.1. Chrome Developer Tools

3.2.2. POSTMAN

3.2.3. HTTPie

Shell
$ http --header http://www.scu.edu.cn
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, max-age=600
Connection: Keep-Alive
Content-Encoding: gzip
Content-Language: zh-CN
Content-Length: 14403
Content-Type: text/html
Date: Sun, 27 May 2018 15:38:25 GMT
ETag: "e6ec-56d3032d70a32-gzip"
Expires: Sun, 27 May 2018 15:48:25 GMT
Keep-Alive: timeout=5, max=100
Last-Modified: Sun, 27 May 2018 13:44:22 GMT
Server: VWebServer
Vary: User-Agent,Accept-Encoding
X-Frame-Options: SAMEORIGIN

3.2.4. BuiltWith:识别网站使用的技术

import builtwith
    print(builtwith.parse('http://www.bootcss.com/'))
    # {'web-servers': ['Nginx'], 'font-scripts': ['Font Awesome'], 'javascript-frameworks': ['Lo-dash', 'Underscore.js', 'Vue.js', 'Zepto', 'jQuery'], 'web-frameworks': ['Twitter Bootstrap']}
 import ssl
     ssl._create_default_https_context = ssl._create_unverified_context
     print(builtwith.parse('https://www.jianshu.com/'))
     # {'web-servers': ['Tengine'], 'web-frameworks': ['Twitter Bootstrap', 'Ruby on Rails'], 'programming-languages': ['Ruby']}

3.2.5. python-whois:查询网站的所有者

   import whois
   whois.whois('baidu.com')
   # {'domain_name': ['BAIDU.COM', 'baidu.com'],'registrar': 'MarkMonitor, Inc.', 'whois_server': 'whois.markmonitor.com', 'referral_url': None, 'updated_date': [datetime.datetime(2017, 7, 28, 2, 36, 28), datetime.datetime(2017, 7, 27, 19, 36, 28)], 'creation_date': [datetime.datetime(1999, 10, 11, 11, 5, 17), datetime.datetime(1999, 10, 11, 4, 5, 17)], 'expiration_date': [datetime.datetime(2026, 10, 11, 11, 5, 17), datetime.datetime(2026, 10, 11, 0, 0)], 'name_servers': ['DNS.BAIDU.COM', 'NS2.BAIDU.COM', 'NS3.BAIDU.COM', 'NS4.BAIDU.COM', 'NS7.BAIDU.COM', 'dns.baidu.com', 'ns4.baidu.com', 'ns3.baidu.com', 'ns7.baidu.com', 'ns2.baidu.com'], 'status': ['clientDeleteProhibited https://icann.org/epp#clientDeleteProhibited', 'clientTransferProhibited https://icann.org/epp#clientTransferProhibited', 'clientUpdateProhibited https://icann.org/epp#clientUpdateProhibited', 'serverDeleteProhibited https://icann.org/epp#serverDeleteProhibited', 'serverTransferProhibited https://icann.org/epp#serverTransferProhibited', 'serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited', 'clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited)', 'clientTransferProhibited (https://www.icann.org/epp#clientTransferProhibited)', 'clientDeleteProhibited (https://www.icann.org/epp#clientDeleteProhibited)', 'serverUpdateProhibited (https://www.icann.org/epp#serverUpdateProhibited)', 'serverTransferProhibited (https://www.icann.org/epp#serverTransferProhibited)', 'serverDeleteProhibited (https://www.icann.org/epp#serverDeleteProhibited)'], 'emails': ['[email protected]', '[email protected]'], 'dnssec': 'unsigned', 'name': None, 'org': 'Beijing Baidu Netcom Science Technology Co., Ltd.', 'address': None, 'city': None, 'state': 'Beijing', 'zipcode': None, 'country': 'CN'}

3.2.6. robotparser:解析robots.txt的工具

 from urllib import robotparser
 parser = robotparser.RobotFileParser()
 parser.set_url('https://www.taobao.com/robots.txt')
 parser.read()
 parser.can_fetch('Hellokitty', 'http://www.taobao.com/article')
 #  False
parser.can_fetch('Baiduspider', 'http://www.taobao.com/article')
 #  True
parser.can_fetch('Baiduspider', 'http://www.taobao.com/product')
 #  False

4. 一个简单的爬虫

一个基本的爬虫通常分为数据采集(网页下载)、数据处理(网页解析)和数据存储(将有用的信息持久化)三个部分的内容,当然更为高级的爬虫在数据采集和处理时会使用并发编程或分布式技术,其中可能还包括调度器和后台管理程序(监控爬虫的工作状态以及检查数据抓取的结果)。

1). 设定抓取目标(种子页面)并获取网页。
2). 当服务器无法访问时,设置重试次数。
3). 在需要的时候设置用户代理(否则无法访问页面)。
4). 对获取的页面进行必要的解码操作。
5). 通过正则表达式获取页面中的链接。
6). 对链接进行进一步的处理(获取页面并重复上面的动作)。
7). 将有用的信息进行持久化(以备后续的处理)。

一 数据采集和解析

序列化 / 反序列化
pickle / json / shelve
pickle: --
json:  dump / dumps(序列化) || load / loads(反序列化)

序列化 - 把对象变成字符,或者字符序列
反序列化 - 把字符或者字符序列还原为对象

数据压缩
zlib: 压缩 compress/解压缩decompress


通过上一个章节,我们已经了解到了开发一个爬虫需要做的工作以及一些常见的问题,至此我们可以对爬虫开发需要做的工作以及相关的技术做一个简单的汇总,可能有些库我们之前并没有使用过,不过别担心,这些内容我们都会讲到的。

  1. 下载数据 - urllib / requests / aiohttp。
  2. 解析数据 - re / lxml / beautifulsoup4(bs4)/ pyquery。
  3. 持久化(需要序列化压缩) - pymysql / redis(高速缓存) / sqlalchemy / peewee / pymongo(结构不严谨的廉价数据,但是数据可能非常庞大)。
  4. 调度器 - 进程 / 线程 / 协程。

事务的隔离级别:
1. UNcommitted read 读未提交,并发性好 -但是会出现读脏数据Dirty Read
2. read Committed - 可以避免脏读,但是不可以重复读, - UNrepeatable read
3. repeatable read 可以重复读 – 但是会出现Phantom Read 幻读
4. serializable -串行,没有并发了

永久更改事务隔离级别: set global transaction isolation level read committed;
临时更改事务隔离级别: set session transaction isolation level serializable;

为什么使用非关系型数据库 redis/MongoDB
CAP理论
对于分布式计算系统,不可能同时满足一下三点:
1. 一致性(consistency)(所有节点在同一时间具有相同的数据)
2. 可用性(availability)(保证每个请求不管成功还是失败都有相应)
3. 分割容忍(Partitiontolerance)(系统中人以信息的丢失或者失败不会影响1系统继续运行)

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。
AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。

二 HTML页面分析

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
        <h1>Hello, world!</h1>
        <p>这是一个神奇的网站!</p>
        <hr>
        <div>
            <h2>这是一个例子程序</h2>
            <p>静夜思</p>
            <p class="foo">床前明月光</p>
            <p id="bar">疑似地上霜</p>
            <p class="foo">举头望明月</p>
            <div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
        </div>
        <a class="foo" href="http://www.qq.com">腾讯网</a>
        <img src="./img/pretty-girl.png" alt="美女">
        <img src="./img/hellokitty.png" alt="凯蒂猫">
        <img src="/static/img/pretty-girl.png" alt="美女">
        <table>
            <tr>
                <th>姓名</th>
                <th>上场时间</th>
                <th>得分</th>
                <th>篮板</th>
                <th>助攻</th>
            </tr>
        </table>
    </body>
</html>

如果你对上面的代码并不感到陌生,那么你一定知道HTML页面通常由三部分构成,分别是:用来承载内容的Tag(标签)、负责渲染页面的CSS(层叠样式表)以及控制交互式行为的JavaScript。通常,我们可以在浏览器的右键菜单中通过“查看网页源代码”的方式获取网页的代码并了解页面的结构;当然,我们也可以通过浏览器提供的开发人员工具来了解网页更多的信息。

三 使用requests获取页面

获取页面源码
    1. requests
        1. GET请求和POST请求。
        2. URL参数和请求头。
        3. 复杂的POST请求(文件上传)。
        4. 操作Cookie。
        5. 设置代理服务器。
        6. 超时设置。
    2. beautifulsoup bs4
    3. scrapy
from urllib.error import URLError
from urllib.request import urlopen

import re
import pymysql
import ssl

from pymysql import Error

# 获取页面的HTML代码(通过递归实现指定次数的重试操作)
def get_page_html(seed_url, *, retry_times=3, charsets=('utf-8',)):
    # 页面初始状态设置为None
    page_html = None
    # 页面的访问不一定成功,为了代码安全,需要try一下
    try:
        page_html = decode_page(urlopen(seed_url).read(), charsets)
    except URLError:
        # logging.error('URL:', error)
        # 判断重试的次数
        if retry_times > 0:
            return get_page_html(seed_url, retry_times=retry_times - 1,
                                 charsets=charsets)
    return page_html

# 通过指定的字符集对获取页面进行解码(不是每个网站都将字符集设置为utf-8)
def decode_page(page_bytes, charsets=('utf-8',)):
    page_html = None
    for charset in charsets:
        # 解码可能不成功,需要try
        try:
            # 如果成功解码就跳出循环,否则就使用字符集charsets中的编码继续进行解码
            page_html = page_bytes.decode(charset)
            break
        except UnicodeDecodeError:
            pass
            # logging.error('Decode:', error)
    return page_html

# 从爬取到的页面提取需要的信息(通常是链接也可以通过正则表达式进行指定)
def get_matched_parts(page_html, pattern_str, pattern_ignore_case=re.I):
    pattern_regex = re.compile(pattern_str, pattern_ignore_case)
    return pattern_regex.findall(page_html) if page_html else []

# 开始执行爬虫程序并对指定的数据进行持久化操作
def start_crawl(seed_url, match_pattern, *, max_depth=-1):
    """
        seed_url:初始的种子url
        match_pattern:匹配的正则表达式
        max_depth:爬取的深度,即对一个页面爬取数据,进入下一级页面,再进入下一级页面的次数
    """
    # conn建立一个数据库连接对象,实现对爬取信息的持久化操作
    conn = pymysql.connect(host='localhost', port=3306,
                           database='crawler', user='root',
                           password='123456', charset='utf8')
    try:
        with conn.cursor() as cursor:
            # 将所有需要爬取的url放入到url_list里面
            url_list = [seed_url]
            # 将已经爬取过得页面放入一个字典
            visited_url_list = {seed_url: 0}
            # 当前url_list不为空时,继续进去页面爬取
            while url_list:
                # 从url_list中爬取一个url,便将其删除
                current_url = url_list.pop(0)
                depth = visited_url_list[current_url]
                # 如果爬取的深度没有达到max_depth,则继续爬取
                if depth != max_depth:
                    page_html = get_page_html(current_url, charsets=('utf-8', 'gbk', 'gb2312'))
                    links_list = get_matched_parts(page_html, match_pattern)
                    param_list = []
                    for link in links_list:
                        if link not in visited_url_list:
                            visited_url_list[link] = depth + 1
                            page_html = get_page_html(link, charsets=('utf-8', 'gbk', 'gb2312'))
                            # 获取到的信息
                            headings = get_matched_parts(page_html, r'<h1>(.*)<span')
                            if headings:
                                param_list.append((headings[0], link))
                    # 批量执行数据库插入数据的操作
                    cursor.executemany('insert into tb_result values (default, %s, %s)',param_list)
                    # 事务提交
                    conn.commit()
    except Error:
        pass
        # logging.error('SQL:', error)
    finally:
        conn.close()


def main():
    # 有的网页需要进行证书验证,我们的requests请求已经自带了很多证书,但是有的网页还是不行,因此需要导入ssl模块,创建一个默认的上下文content,并且将其置为unverified,即不需要验证
    ssl._create_default_https_context = ssl._create_unverified_context
    start_crawl('http://sports.sohu.com/nba_a.shtml',
                r'<a[^>]+test=a\s[^>]*href=["\'](.*?)["\']',
                max_depth=2)


if __name__ == '__main__':
    main()

说明:关于requests的详细用法可以参考它的官方文档

四 四种采集方式

四种采集方式的比较

抓取方法 速度 使用难度 备注
正则表达式 困难 常用正则表达式
在线正则表达式测试
lxml 一般 需要安装C语言依赖库
唯一支持XML的解析器
Beautiful 快/慢(取决于解析器) 简单
PyQuery 较快 简单 Python版的jQuery

说明:Beautiful的解析器包括:Python标准库(html.parser)、lxml的HTML解析器、lxml的XML解析器和html5lib。

五 BeautifulSoup的使用

  1. 遍历文档树
    • 获取标签
    • 获取标签属性
    • 获取标签内容
    • 获取子(孙)节点
    • 获取父节点/祖先节点
    • 获取兄弟节点
  2. 搜索树节点
    • find / find_all:字符串、正则表达式、列表、True、函数或Lambda。
    • select_one / select:CSS选择器
    • find和select_one获取的都是一个节点
    • find_all与select获取的是多个节点,以列表形式返回

说明:更多内容可以参考BeautifulSoup的官方文档

from bs4 import BeautifulSoup
import re

def main():
# 这里为了方便演示,直接获取了一个html的页面源码,并且赋值给html
    html = """
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>首页</title>
        </head>
        <body>
            <h1>Hello, world!</h1>
            <p>这是一个<em>神奇</em>的网站!</p>
            <hr>
            <div>
                <h2>这是一个例子程序</h2>
                <p>静夜思</p>
                <p class="foo">床前明月光</p>
                <p id="bar">疑似地上霜</p>
                <p class="foo">举头望明月</p>
                <div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
            </div>
            <a class="foo" href="http://www.qq.com">腾讯网</a>
            <img src="./img/pretty-girl.png" alt="美女">
            <img src="./img/hellokitty.png" alt="凯蒂猫">
            <img src="/static/img/pretty-girl.png" alt="美女">
            <table>
                <tr>
                    <th>姓名</th>
                    <th>上场时间</th>
                    <th>得分</th>
                    <th>篮板</th>
                    <th>助攻</th>
                </tr>
            </table>
        </body>
    </html>
    """
    # 通过BeautifulSoup构建一个DOM对象,(可通过参数指定解析器,解析器优劣见上文)
    # 之后我们就可以对soup对象进行各种寻根问祖的节点操作
    soup = BeautifulSoup(html, 'lxml')
    # 类似于JavaScript中 - document.title    
    print(soup.title) # 可以直接获取title标签
    # <title>首页</title>

    # 类似于JavaScript中 - document.body.h1
    print(soup.p) # 获取第一个p标签
    # <p>这是一个<em>神奇</em>的网站!</p>

    print(soup.body.p.text) # 获取body标签下p标签的内容text
    # 这是一个神奇的网站!

    print(soup.body.p.contents) # 获取body标签下p标签的所有直接子节点并且以列表形式返回
    # ['这是一个', <em>神奇</em>, '的网站!']

    # .children方法获取了p标签的所有直接子节点
    for p_child in soup.body.p.children:
        print(p_child)
    # .contents与.children方法类似,只是.contents返回列表,.children返回一个生成器,需要进行遍历才能拿到相应的数据。.descendants则拿到的是所有的子孙节点

    print(len([elem for elem in soup.body.children]))  # 获取body下所有直接子节点数量
    # 19
    print(len([elem for elem in soup.body.descendants]))# 获取body下所有的子节点的数量
    # 65
    print([elem for elem in soup.body.descendants]) # 获取body下所有的子节点   

    # findAll与find_all都是相同的函数,只是写法不同
    print(soup.findAll(re.compile(r'^h[1-6]'))) # 获取所有的h1-h6的标签

    print(soup.body.find_all(r'^h')) # 获取body标签下所有以h打头的标签

    print(soup.body.div.find_all(re.compile(r'^h'))) # 获取body标签下第一个div标签中所有的h打头的标签

    print(soup.find_all(re.compile(r'r$'))) # 获取所有以r结尾的标签

    # 获取所有标签为‘img’,‘src’属性符合正则表达式(r'\./img/\w+.png')的标签
    print(soup.find_all('img', {'src':re.compile(r'\./img/\w+.png')}))  

    # 获取有两个属性attrs的所有标签
    print(soup.find_all(lambda x: len(x.attrs) == 2))

    # 获取所有的foo标签
    print(soup.find_all(foo))

    # 获取所有class=foo的p标签
    print(soup.find_all('p', {'class': 'foo'}))

    # 获取所有的a标签的href属性,并对其进行遍历
    for elem in soup.select('a[href]'):
        print(elem.attrs['href'])

def foo(elem):
    return len(elem.attrs) == 2

if __name__ == '__main__':
    main()

六 进行代理以及伪装自己的请求

实例1:

def get_html(url):
    # 这里我们给url请求,伪装了一个请求头,表示我是一个浏览器(也可以伪装成移动端)
    resp = requests.get(url,headers={
    'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1'})
    return resp

常见的伪装‘user-agent’:
常见的User Agent
1.Android
* Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19
* Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300 Build/IMM76D) * * * AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
* Mozilla/5.0 (Linux; U; Android 2.2; en-gb; GT-P1000 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
2.Firefox
* Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
* Mozilla/5.0 (Android; Mobile; rv:14.0) Gecko/14.0 Firefox/14.0
3.Google Chrome
* Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36
* Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19
4.iOS
* Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3
* Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A101a Safari/419.3

实例2:

def get_html(url):
    # 这里我们的url请求,伪装成百度的爬虫
    resp = requests.get(url,headers={
    'user-agent': 'Baiduspider'})
    return resp

实例3:

def main():
    这里我使用了代理的IP,隐藏了自己的真实ip
    headers = {'user-agent': 'Baiduspider'}
    # 隐藏自己的身份IP
    proxies = {
        # 代理IP 'http': '36.22.76.233:35390',
        'http': '61.135.217.7:80'
    }
    base_url = 'https://www.zhihu.com'
    seed_url = urljoin(base_url, 'explore')

    resp = requests.get(seed_url, headers=headers, proxies=proxies)

猜你喜欢

转载自blog.csdn.net/qq_41772997/article/details/80500687