网络爬虫入门笔记
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)
- User-Agent: 可以用于伪装成浏览器
-
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
异常
异常 | 说明 |
---|---|
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: <>...</>中字符串区域的检索字符串
实战之大学排名爬取
注意一个数据输出时的格式化格式
代码如下
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.I 或 re.IGNORECASE |
忽略正则表达式的大小写,[A‐Z]能够匹配小写字符 |
re.M 或 re.MULTILINE |
正则表达式中的^操作符能够将给定字符串的每行当作匹配开始 |
re.S 或 re.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爬虫框架
框架结构
在其中用户只需编写/配置 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] |
EntyEnty520~