Python初窥爬虫

前言

来张爬取的镇楼
在这里插入图片描述

大创需要用到爬虫,当时学python没有系统学过,在这里自己自学一下,做个笔记方便日后复习,若有不对,还请斧正"🐂"

入门

通过urliib.request.urlopen()函数访问页面

安装库

在命令提示符输入pip+list可以看自己安装了哪些库

需要安装以下库:

  • request:通过http请求获取页面
  • lxml:支持html和xml的解析,支持xpath解析,效率高
  • Beautiful Soup4:可以从html或xml中提取数据

没有的在终端输入以下命令

    python -m pip install beautifulsoup4
    python -m pip install lxml
    python -m pip install requests
什么是编码

html.decode(“utf-8”)可以解码变成Unicode编码,再从encode()编码成另一种编码

实战

  1. urlopen里面有:
  • geturl()返回请求的url
  • info()返回一个httplib.HTTPMessage对象
  • getcode()返回HTTP状态码
  • read()读取内容
  1. GET是从服务器请求数据
    POST是向服务器提交被处理的数据
  2. urlopen()中的data参数,该参数赋值的话,HTTP请求就是用POST方式,若是NULL默认值,HTTP请求就是GET方式
  3. json.loads()用来解析JSON格式的字符串【变成一个字典】

隐藏

修改User-Agent

  1. 实例化request对象的时候将headers参数传进去
  2. add_header()往request对象添加headers

延迟提交数据

用time模块,但效率低
eg:time.sleep()

使用代理

  1. proxy_support=urllib.request.ProxyHandler({})
  2. opener=urllib.request.build_ioener(proxy_support)
  • build_opener()可以创建私人定制的opener
  1. urllib.request.install_opener(opener)
  • 将定制好的opener安装到系统上
  • 不想换掉默认,可以用opener.open()的方式打开网页

Beautiful Soup

BeautifulSoup(html,“html.parser”)有两个参数,前者是需要提取的HTML或者XML文件,后者是指定解析器

正则表达式

“当你发现一个问题可以用正则表达式来解决的时候,于是你就有了两个问题——王涛” 🐂🐎

re模块

search()方法用于在字符串中搜索正则表达式第一次出现的位置,找不到返回None

通配符

可以用(,)表示,可以匹配除了换行符之外的任何字符

反斜杠

反斜杠可以剥夺元字符的特殊能力,还能使普通字符拥有特殊能力

字符类

  • 表示一个字符的范围,用中括号打包起来;字符类中的任何一个字符匹配,就算匹配成功
  • [ ]里面可以用“-”表示范围

重复匹配

  • 用{}对元字符实现重复匹配功能
  • 重复的次数也可以取一个范围;eg{3,5}

特殊符号及用法

特殊符号有:元字符和“\”+普通字符

元字符

  • .表示匹配除换行符之外的任何字符
  • |表示逻辑或操作
  • ^表示匹配字符串的开始位置
  • $表示匹配字符串的结束位置
  • \可以剥夺元字符的特殊能力,还能使普通字符拥有特殊能力
  • “\” +(1~99)的数字表示引用序号对应的子组所匹配的字符串
  • “\” +三位数字,表示这个八进制数对应的ASCII字符
  • [ ]表示生成一个字符类,包围在里面的元字符都失去了特殊功能【除了几个特殊字符:-(表示范围) \(表示转义) ^(表示取反)】
  • { }表示做重复事情【表示重复的元字符还有(*){0,}, (+){1,},(?)=={0,1}】
    正则表达式不要随便加空格

贪婪与非贪婪

正则表达式默认启用贪婪匹配模式
启用非贪婪模式:重复元素后面加(?)

反斜杠+普通字母=特殊含义

  • “\” +(1~99)的数字表示引用序号对应的子组所匹配的字符串
  • “\” +三位数字,表示这个八进制数对应的ASCII字符
  • (\A)==(^)
  • (\Z)==($)
  • \b表示匹配一个单词的边界
  • \B表示匹配一个非单词的边界
  • \d表示匹配的是Unicode中定义的数字字符
  • \D表示匹配的是非Unicode中定义的数字字符
    ……

编译正则表达式

重复使用某个正则表达式,用 re.compile() 方法编译成模式对象

编译标志

通过编译标志,可以修改正则表达式的工作方式

实用的方法

  1. re.search() 不会立刻返回你可以使用的字符串,取而代之的是一个匹配对象,这时候用 group() 才可以获得匹配的字符串
  2. start() 返回匹配的开始位置;end() 返回匹配的结束位置;span() 返回匹配的范围
  3. findall() 找到所有匹配的内容,组织成列表返回
  4. finditer() 会将结果返回一个迭代器,方便以迭代的方式获取
  5. sub() 实现字符串的替换

异常处理

URLError

HTTPError

404 页面无法找到
403 请求终止
401 验证请求

处理异常

实例

os模块
方法解释
os.getcwd()查看当前工作工作目录
os.listdir()查看某个目录下的文件列表
os.chdir(‘fileUrl’)修改工作目录
os.mkdir(’ ’)创建单层目录
os.makedirs(‘fileurl’)创建多级文件目录
os.remove(’’)删除文件
os.rmdir(’’)删除单层文件目录
os.removedirs(’’)递归尝试删除多级空文件目录
os.rename(’’)更名文件目录
os.system(’’)模拟shell命令
os.pardir指代上一级文件目录
os.curdir指代当前目录
requests模块
方法解释
requests.request()构造一个请求,支持以下各种方法
requests.get()获取html的主要方法
requests.head()获取html头部信息的主要方法
requests.post()向html网页提交post请求的方法
requests.put()向html网页提交put请求的方法
requests.patch()向html提交局部修改的请求
requests.delete()向html提交删除请求
re模块
用途
  • 测试字符串内的模式。
  • 替换文本
  • 基于模式匹配从字符串中提取子字符串。
语法
'.'     匹配所有字符串,除\n以外
'-'     表示范围[0-9]
'*'     匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*'+'     匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+
'^'     匹配字符串开头
'$'     匹配字符串结尾 re
'\'     转义字符, 使后一个字符改变原来的意思,如果字符串中有字符*需要匹配,可以\*或者字符集[*] re.findall(r'3\*','3*ds')结['3*']
'*'     匹配前面的字符0次或多次 re.findall("ab*","cabc3abcbbac")结果:['ab', 'ab', 'a']
'?'     匹配前一个字符串0次或1次 re.findall('ab?','abcabcabcadf')结果['ab', 'ab', 'ab', 'a']
'{m}'   匹配前一个字符m次 re.findall('cb{1}','bchbchcbfbcbb')结果['cb', 'cb']
'{n,m}' 匹配前一个字符n到m次 re.findall('cb{2,3}','bchbchcbfbcbb')结果['cbb']
'\d'    匹配数字,等于[0-9] re.findall('\d','电话:10086')结果['1', '0', '0', '8', '6']
'\D'    匹配非数字,等于[^0-9] re.findall('\D','电话:10086')结果['电', '话', ':']
'\w'    匹配字母和数字,等于[A-Za-z0-9] re.findall('\w','alex123,./;;;')结果['a', 'l', 'e', 'x', '1', '2', '3']
'\W'    匹配非英文字母和数字,等于[^A-Za-z0-9] re.findall('\W','alex123,./;;;')结果[',', '.', '/', ';', ';', ';']
'\s'    匹配空白字符 re.findall('\s','3*ds \t\n')结果[' ', '\t', '\n']
'\S'    匹配非空白字符 re.findall('\s','3*ds \t\n')结果['3', '*', 'd', 's']
'\A'    匹配字符串开头
'\Z'    匹配字符串结尾
'\b'    匹配单词的词首和词尾,单词被定义为一个字母数字序列,因此词尾是用空白符或非字母数字符来表示的
'\B'    与\b相反,只在当前位置不在单词边界时匹配
[]      是定义匹配的字符范围。比如 [a-zA-Z0-9] 表示相应位置的字符要匹配英文字符和数字。[\s*]表示空格或者*'(?P<name>...)'  分组,除了原有编号外在指定一个额外的别名 
Eg:      re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{8})","371481199306143242").groupdict("city") 
结果{'province': '3714', 'city': '81', 'birthday': '19930614'}
方法解释
re.compile()编译正则表达式模式,返回一个对象
re.match()尝试从一个字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,则返回None
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号
re.search()扫描整个字符串并返回第一个成功的匹配
re.sub()用于替换字符串中的匹配项
findall()在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表
re.finditer()在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回
re.split()按照能够匹配的子串将字符串分割后返回列表
BeautifulSoup模块
方法解释
find_all()根据标签,属性,内容查找文档

Begin~~~

爬取网址彼岸桌面
列表页规则为 http://www.netbian.com/mei/index_{页码}.htm

实现目标

  • 生成所有列表页 URL 地址;
  • 遍历列表页 URL 地址,并获取图片详情页地址;
  • 进入详情页获取大图;
  • 保存图片;
  • 得到 2000 张图片之后,开始欣赏。

具体详解参见代码注释

import requests
import re
import time
# 请求函数
def request_get(url, ret_type="text", timeout=5, encoding="GBK"):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
    }
    res = requests.get(url=url, headers=headers, timeout=timeout)
    res.encoding = encoding
    if ret_type == "text":
        return res.text
    elif ret_type == "image":
        return res.content

# 抓取函数
def main():
    n = int(input('请输入爬取的页数:'))
    urls = [f"http://www.netbian.com/mei/index_{i}.htm" for i in range(2, n)]
    url = "http://www.netbian.com/mei/index.htm"
    urls.insert(0, url)
    for url in urls:
        print("抓取列表页地址为:", url)
        text = request_get(url)
        format(text)

# 解析函数
def format(text):
    origin_text = split_str(text, '<div class="list">', '<div class="page">')
    pattern = re.compile('href="(.*?)"')
    hrefs = pattern.findall(origin_text)
    hrefs = [i for i in hrefs if i.find("desk") > 0]
    for href in hrefs:
        url = f"http://www.netbian.com{href}"
        print(f"正在下载:{url}")
        text = request_get(url)
        format_detail(text)

def split_str(text, s_html, e_html):
    start = text.find(s_html) + len(e_html)
    end = text.find(e_html)
    origin_text = text[start:end]
    return origin_text

def format_detail(text):
    origin_text = split_str(text, '<div class="pic">', '<div class="pic-down">')
    pattern = re.compile('src="(.*?)"')
    image_src = pattern.search(origin_text).group(1)
    # 保存图片
    save_image(image_src)

# 存储函数
def save_image(image_src):
    content = request_get(image_src, "image")
    with open(f"{str(time.time())}.jpg", "wb") as f:
        f.write(content)
        print("图片保存成功")

if __name__ == '__main__':
    main()

效果如下
在这里插入图片描述

总结

QAQ 依旧是菜的一天

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WTcrazy _

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值