网络爬虫入门笔记

Requests库

方法

方法 说明
requests.request() 构造一个请求,支撑以下各方法的基础方法
requests.get() 对应于HTTP的GET
requests.head() 对应于HTTP的HEAD,获取HTML网页头信息的方法
requests.post() 对应于HTTP的POST
requests.put() 对应于HTTP的PUT
requests.patch() 对应于HTTP的PATCH,向HTML网页提交局部修改请求
requests.delete() 对应于HTTP的DELETE

格式为

requests.get(url, params=None, **kwargs)
requests.head(url, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.delete(url, **kwargs)

其中

  • params: 字典或字节序列,作为参数增加到url中
  • **kwargs: 12个控制访问的参数
    • data: 字典、字节序列或文件对象,作为Request的内容

    • json: JSON格式的数据,作为Request的内容

    • headers: 字典,HTTP定制头

      • User-Agent: 可以用于伪装成浏览器
        kv = {'user-agent': 'Mozilla/5.0'}
        r = requests.get(url, headers=kv)
        
    • cookies: 字典或CookieJar,Request中的cookie

    • auth: 元组,支持HTTP认证功能

    • files: 字典类型,传输文件

    • timeout: 设定超时时间,秒为单位

    • proxies: 字典类型,设定访问代理服务器,可以增加登录认证

    • allow_redirects: True/False,默认为True,重定向开关

    • stream: True/False,默认为True,获取内容立即下载开关

    • verify: True/False,默认为True,认证SSL证书开关

    • cert: 本地SSL证书路径

Response对象

Response 对象具有以下属性

  • r.status_code: HTTP请求的返回状态,200表示连接成功,404表示失败
  • r.text
  • r.encoding: 从HTTP header中猜测的响应内容编码方式
  • r.apparent_encoding: 从内容中分析出的响应内容编码方式(备选编码方式)
  • r.content: 这是二进制形式,不同于r.text

image-20231113165318827

异常

异常 说明
requests.ConnectionError 网络连接错误异常,如DNS查询失败、拒绝连接等
requests.HTTPError HTTP错误异常
requests.URLRequired URL缺失异常
requests.TooManyRedirects 超过最大重定向次数,产生重定向异常
requests.ConnectTimeout 连接远程服务器超时异常
requests.Timeout 请求URL超时,产生超时异常

一个处理异常的框架代码

def getHTMLText(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status() # 如果状态不是200,引发HTTPError异常
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return "产生异常"

Robots协议

参考一个京东的 robots协议

User‐agent: *
Disallow: /?*
Disallow: /pop/*.html
Disallow: /pinpai/*.html?*
User‐agent: EtaoSpider
Disallow: /
User‐agent: HuihuiSpider
Disallow: /
User‐agent: GwdangSpider
Disallow: /
User‐agent: WochachaSpider
Disallow: /

Beautiful Soup库

基本元素

看以下的例子,基本上就知道基本元素怎么用了

>>> demo = requests.get("https://python123.io/ws/demo.html").text
>>> demo
'<html><head><title>This is a python demo page</title></head>\r\n<body>\r\n<p class="title"><b>The demo python introduces several python courses.</b></p>\r\n<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n<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>\r\n</body></html>'
>>> from bs4 import BeautifulSoupfrom
>>> soup = BeautifulSoup(demo, "html.parser")
>>> soup.title
<title>This is a python demo page</title>
>>> tag = soup.a # 如果有多个则对应第一个
>>> tag 
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>
>>> tag.name
'a'
>>> tag.attrs
{'href': 'http://www.icourse163.org/course/BIT-268001', 'class': ['py1'], 'id': 'link1'}
>>> tag.string
'Basic Python'
>>> tag.parent.name
'p'
>>> newsoup = BeautifulSoup("<b><!--This is a comment--></b><p>This is not a comment</p>", "html.parser")
>>> newsoup.b.string
'This is a comment'
>>> type(newsoup.b.string)
<class 'bs4.element.Comment'>
>>> newsoup.p.string
'This is not a comment'
>>> type(newsoup.p.string)
<class 'bs4.element.NavigableString'>

遍历方式

  • 上行: .parent, .parents
  • 下行: .contents, .children, .descendants
  • 平行: .next_sibling, .previous_sibling, .next_siblings, .previous_siblings
    其中 .contents 返回一个列表, 其他返回一个元素或者迭代器

信息提取

<tag>(..) 等价于 <tag>.find_all(..)
soup(..) 等价于 soup.find_all(..)
标准格式为

<>.find_all(name, attrs, recursive, string, **kwargs)

返回一个列表类型,存储查找的结果,其中

  • name: 对标签名称的检索字符串
  • attrs: 对标签属性值的检索字符串,可标注属性检索
  • recursive: 是否对子孙全部检索,默认为True
  • string: <>...</>中字符串区域的检索字符串

实战之大学排名爬取

注意一个数据输出时的格式化格式

image-20231113210534390

代码如下

import requests
import bs4
from bs4 import BeautifulSoup


def getHTMLText(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()  # 如果状态不是200,引发HTTPError异常
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return "Exception"


def fillUnivList(ulist, html):
    soup = BeautifulSoup(html, "html.parser")
    for tr in soup.find('tbody').children:
        if isinstance(tr, bs4.element.Tag):  # 判断tr是否为bs4库中的Tag类型
            name_cn = tr.find_all(attrs={'class': 'name-cn'}, recursive=True)[0].get_text(strip=True)
            td = tr.find_all('td')
            UnivRank = td[0].get_text(strip=True)
            UnivLocation = td[2].get_text(strip=True)
            UnivType = td[3].get_text(strip=True)
            # 去除空格
            ulist.append([UnivRank, name_cn, UnivLocation, UnivType])


def printUnivList(ulist, num):
    print("{:^10}\t{:^20}\t{:^10}\t{:^10}".format("排名", "学校名称", "所在地", "类型"))
    for i in range(num):
        u = ulist[i]
        print("{:^10}\t{:^20}\t{:^10}\t{:^10}".format(u[0], u[1], u[2], u[3]))


def main():
    uinfo = []
    url = "https://www.shanghairanking.cn/rankings/bcur/2023"
    html = getHTMLText(url)
    fillUnivList(uinfo, html)
    printUnivList(uinfo, 20)  # 20 univs


if __name__ == '__main__':
    main()

Re库

正则表达式操作符

操作符 说明 实例
. 表示任何单个字符
[] 字符集,对单个字符给出取值范围 [abc]表示a、b、c,[a‐z]表示a到z单个字符
[^] 非字符集,对单个字符给出排除范围 [^abc]表示非a或b或c的单个字符
* 前一个字符0次或无限次扩展 abc*表示ab、abc、abcc、abccc等
+ 前一个字符1次或无限次扩展 abc+表示abc、abcc、abccc等
? 前一个字符0次或1次扩展 abc?表示ab、abc
| 左右表达式任意一个 abc|def表示abc、def
扩展前一个字符m次 ab{2}c表示abbc
扩展前一个字符m至n次(含n) ab{1,2}c表示abc、abbc
^ 匹配字符串开头 ^abc表示abc且在一个字符串的开头
$ 匹配字符串结尾 类似^
() 分组标记,内部只能使用|操作符 (abc)表示abc,(abc|def)表示abc、def
\d 数字,等价于[0‐9]
\w 单词字符,等价于[A‐Za‐z0‐9_]

经典正则表达式

正则表达式 功能
^[A‐Za‐z]+$ 由26个字母组成的字符串
^[A‐Za‐z0‐9]+$ 由26个字母和数字组成的字符串
^-?[0‐9]+$ 整数形式的字符串
^[0‐9]*[1‐9][0‐9]*$ 正整数形式的字符串
[1‐9]\d 中国境内邮政编码,6位
[\u4e00‐\u9fa5] 匹配中文字符

Re库的主要功能函数

函数 说明
re.search(pattern, string, flags=0) 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match(pattern, string, flags=0) 从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall(pattern, string, flags=0) 搜索字符串,以列表类型返回全部能匹配的子串
re.split(pattern, string, maxsplit=0, flags=0) 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
re.finditer(pattern, string, flags=0) 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
re.sub(pattern, repl, string, count=0, flags=0) 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串

其中 flags 是正则表达式使用时的控制标记

标记 说明
re.Ire.IGNORECASE 忽略正则表达式的大小写,[A‐Z]能够匹配小写字符
re.Mre.MULTILINE 正则表达式中的^操作符能够将给定字符串的每行当作匹配开始
re.Sre.DOTALL 正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符

此外,也可以先编译正则表达式再使用,这样可以节省时间

pat = re.compile(r'[1‐9]\d{5}')
r = pat.search('BIT 100081')

对于match对象,参考下面的例子

>>> import re
>>> match = re.search(r'[1‐9]\d{5}', 'BIT100081 TSU100084')
>>> match.string
'BIT100081 TSU100084'
>>> match.re        # 匹配时使用的patter对象(正则表达式)
re.compile('[1‐9]\\d{5}')
>>> match.pos
0
>>> match.endpos
19
>>> match.group(0)  # 获得匹配后的字符串
'100081'
>>> match.start()
3
>>> match.end()
9
>>> match.span()
(3, 9)

贪婪匹配与最小匹配

Re库默认是贪婪匹配,可以在后面加上?来实现最小匹配

>>> match = re.search(r'PY.*N', 'PYANBNCNDN')
>>> match.group(0)
'PYANBNCNDN'
>>> match = re.search(r'PY.*?N', 'PYANBNCNDN')
>>> match.group(0)
'PYAN'

Scrapy爬虫框架

框架结构

image-20231114120121262

在其中用户只需编写/配置 Item Pipelines 和 Spiders

常用命令

命令 说明 格式
startproject 创建一个新的工程 scrapy startproject <name> [dir]
genspider 创建一个新的爬虫 scrapy genspider [options] <name> <domain>
settings 获取配置信息 scrapy settings [options]
crawl 运行一个爬虫 scrapy crawl <spider>
list 列出工程中所有爬虫 scrapy list [options]
view 用浏览器查看一个response scrapy view <url>
shell 启动URL调试命令行 scrapy shell [url]
posted @ 2023-11-13 19:40  520Enterprise  阅读(33)  评论(0编辑  收藏  举报