Python爬虫基本使用与简单实例

Requests库

Requests库的7个主要方法

方法说明
requests.request()构造请求
requests.get()获取网页的主要方法
requests.head()获取网页头信息
requests.post()向网页提交POST请求
requests.put()向网页提交PUT请求
requests.patch()向网页提交局部修改请求
requests.delete()向网页提交删除请求
request()方法
requests.request(method, url, **kwargs) #完整参数
params:字典或字节序列,作为参数增加到url中
kv = {'key1': 'value1', 'key2': 'value2'}
r = requests.request('GET', 'http://python123.io/ws', params=kv)
print(r.url)
#http://python123.io/ws?key1=value1&key2=value2
data:字典、字节序列或文件对象,作为Request的内容
kv = {'key1': 'value1', 'key2': 'value2'}
r = requests.request('POST', 'http://python123.io/ws', data=kv)
body = '主体内容'
r = requests.request('POST', 'http://python123.io/ws', data=body)
json:JSON格式数据,作为Request的内容
kv = {'key1': 'value1'}
r = requests.request('POST', 'http://python123.io/ws', json=kv)
headers:字典,HTTP定制头
hd = {'user-agent': 'Chrome/10'}
r = requests.request('POST', 'http://python123.io/ws', headers=hd)
其他

cookies:字典或CookieJar,Request中的cookie
auth:元组,支持HTTP认证功能
files:字典类型,传输文件
timeout:设置超时时间,秒为单位
proxies:字典类型,设定访问代理服务器,可以增加登录认证
allow_redirects:True/False,重定向开关
stream:True/False,获取内容立即下载开关

fs = {'file': open('data.xls', 'rb')}
r = requests.request('POST', 'http://python123.io/ws', files=fs)

pxs = {'http': 'http://user:pass@10.10.10.1:1234'  #用户名和密码的设置
       'https': 'http://10.10.10.1:4321' }   #代理服务器IP地址
r = requests.request('GET', 'http://www.baidu.com', proxies=pxs)
get()方法

通过给定url,构造一个向服务器请求资源的Request对象
返回一个包含服务器资源的Response对象,这里用r表示

r = requests.get(url)
requests.get(url, params=None, **kwargs)    #完整参数
Response对象
import requests
r = requests.get("http://www.baidu.com)
print(r.status_code)    
属性说明
r.status_codeHTTP请求返回的状态,只有200表示连接成功
r.textHTTP响应内容的字符串形式,即url对应的页面内容
r.encoding从HTTP header中猜测的响应内容编码方式
r.apparent_encoding从内容中分析出的响应内容编码方式
r.contentHTTP响应内容的二进制形式

Requests库的异常

异常说明
requests.ConnectionError网络连接错误异常
requests.HTTPErrorHTTP错误异常
requests.URLRequiredURL缺失异常
requests.TooManyRedirects超过最大重定向次数
requests.ConnecTimeout连接远程服务器超时异常
requests.Timeout请求URL超时

r.raise_for_status():如果不是200,产生异常requests.HTTPError

通用代码框架

import requests
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 "产生异常"

if __name__ == "__main__":
    url = "http://www.baidu.com"
    print(getHTMLText(url))

__name__是一个系统变量。假如当前模块是主模块(也就是调用其他模块的模块),那么此模块名字就是__main__,通过if判断这样就可以执行“__mian__”后面的主函数内容;假如此模块是被import的,则此模块名字为文件名字(不加后面的.py),通过if判断这样就会跳过“__mian__”后面的内容

实例

爬取京东商品信息
import requests
url = "https://item.jd.com/100008348546.html"
try:
    r = requests.get(url)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.text[:2000])
except:
    print("爬取失败")
修改头部信息,模拟浏览器访问
import requests
url = "https://www.amazon.cn/gp/product/B01M8L5Z3Y"
try:
    kv = {'user-agent': 'Mozilla/5.0'}
    r = requests.get(url, headers=kv)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.text[1000:2000])
except:
    print("爬取失败")
关键词提交

百度关键词接口:
http://www.baidu.com/s?wd=keyword

import requests
keyword = "Python"
try:
    kv = {'wd': keyword}
    r = requests.get("http://www.baidu.com/s", params=kv)
    print(r.request.url)
    r.raise_for_status()
    print(len(r.text))
except:
    print("爬取失败")
网络图片爬取
import requests
import os
url = "http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg"
root = "C://Users/小涛/Pictures/Saved Pictures/"
path = root + url.split('/')[-1]
try:
    if not os.path.exists(root):
        os.mkdir(root)
    if not os.path.exists(path):
        r = requests.get(url)
        with open(path, 'wb') as f:
            f.write(r.content)
            print("文件保存成功")
    else:
        print("文件已存在")
except:
    print("爬取失败")
IP地址归属地自动查询
import requests
url = "http://m.ip138.com/ip.asp?ip="
try:
    r = requests.get(url + '222.41.155.45')
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.text[-500:])
except:
    print("爬取失败")

Beautiful Soup库

import requests
from bs4 import BeautifulSoup
url = "https://python123.io/ws/demo.html"
r = requests.get(url)
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
print(soup.prettify())

Beautiful Soup类基本元素

基本元素说明
Tag标签,最基本的信息组织单元,用<></>标明开头和结尾
Name标签的名字,<p>...</p>的名字是'p',格式:<tag>.name
Attributes标签的属性,字典形式组织,格式:<tag>.attrs
NavigableString标签内非属性字符串,<>...</>中字符串,格式<tag>.string
Comment标签内字符串的注释部分

标签树的遍历

下行遍历
属性说明
.contents子节点的列表,将<tag>所有儿子结点存入列表
.children子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
.descendants子孙结点的迭代类型,包含所有子孙节点,用于循环遍历

遍历儿子节点

for child in soup.body.children:
    print(child)

遍历子孙结点

for child in soup.body.descendants:
    print(child)
上行遍历
属性说明
.parent节点的父亲标签
.parents节点先辈标签的迭代类型,用于循环遍历先辈节点
for parent in soup.a.parents:
    if parent is None:
        print(parent)
    else:
        print(parent.name)
平行遍历

平行遍历发生在用一个父亲节点下

属性说明
.next_sibling返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling返回按照HTML文本顺序的上一个平行节点标签
.next_siblings迭代类型,返回按照HTML文本顺序的后序所有平行节点标签
.previous_siblings迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

遍历后续节点

for sibling in soup.a.next_siblings:
    print(sibling)

遍历前续节点

for sibling in soup.a.previous_siblings:
    print(sibling)

信息提取一般方法

提取HTML中所有URL链接

  1. 搜索到所有的<a>标签
  2. 解析<a>标签格式,提取href后的链接内容
import requests
from bs4 import BeautifulSoup
url = "https://python123.io/ws/demo.html"
r = requests.get(url)
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
for link in soup.find_all('a'):
    print(link.get('href'))
<>.find_all

<>.find_all(name, attrs, recursive, string, **kwargs)
返回一个列表类型,存储查找结果

  • name:对标签名称的检索字符串
soup.find_all(['a','b'])   #同时查找a,b标签

for tag in soup.find_all(True):     #显示文档中所有标签名称
    print(tag.name)
  • attrs:对标签属性值的检索字符串,可标注属性检索
  • recursive:是否对子孙全部检索,默认True
  • string:<>...</>中字符串区域的检索字符串

正则表达式

语法

操作符说明实例
.表示任何单个字符
[]字符集,对单个字符给出取值范围[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}扩展前一个字符m次ab{2}c表示abbc
{m,n}扩展前一个字符m到n次ab{1,2}c表示abc、abbc
^匹配字符串开头^abc表示abc且在一个字符串的开头
$匹配字符串的结尾abc$表示abc且在一个字符串的结尾
()分组标记,内部只能使用|操作符(abc|def)表示abc或def
\d数字,等价于[0-9]
\w单词字符,等价与[A-Za-z0-9_]

语法实例

正则表达式对应字符串
P(Y|YT|YTH|YTHO)?N'PN','PYN','PYTN','PYTHN','PYTHON'
PYTHON+'PYTHON','PYTHONN','PYTHONNN'...
PY[TH]ON'PYTON','PYHON'
PY[^TH]?ON'PYON','PYaON','PYbON'...
PY{:3}N'PN','PYN','PYYN','PYYYN'
^[A-Za-z]+$由26个字母组成的字符串
^-?\d+$整数形式的字符串
^[0-9]*[1-9][0-9]*$正整数形式的字符串
匹配IP地址的正则表达式

0-99:[1-9]?\d
100-199:1\d{2}
200-249:2[0-4]\d
250-255:25[0-5]
(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]]).){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]])

Re库

正则表达式的表示类型采用raw string类型,不会把转义字符理解为转义字符

主要功能函数
函数说明
re.search()在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match()从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall()搜索字符串,以列表类型返回全部能匹配的字符串
re.split()将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
re.finditer()搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
re.sub()在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
  • re.search(pattern, string, flags=0)
    pattern:正则表达式的字符串
    string:待匹配字符串
    flags:正则表达式使用时的控制标记
    • re.I:忽略大小写
    • re.M:正则表达式中的^操作符能够将给定字符串的每行当作匹配开始
    • re.S:正则表达式中的.操作符能够匹配所有字符(默认匹配除换行符外的所有字符)
import re
match = re.search(r'[1-9]\d{5}', 'BIT 100081')
if match:
    print(match.group(0))

#re.match(pattern, string, flags=0)
match = re.match(r'[1-9]\d{5}', '100081 BIT')
if match:
    print(match.group(0))

#re.findall(pattern, string, flags=0)
ls = re.findall(r'[1-9]\d{5}', 'BIT100081 TSU100084')
print(ls)

#re.split(pattern, string, maxsplit=0, flags=0)
#maxsplit:最大分割数,剩余部分作为最后一个元素输出
ls = re.split(r'[1-9]\d{5}', 'BIT100081 TSU100084', maxsplit=1)
print(ls)

#re.finditer(pattern, string, flags=0)
for m in re.finditer(r'[1-9]\d{5}', 'BIT100081 TSU100084'):
    if m:
        print(m.group(0))

#re.sub(pattern, repl, string, count=0, flags=0)
#repl:替换匹配字符串的字符串
#count:匹配的最大替换次数
print(re.sub(r'[1-9]\d{5}', ':zipcode', 'BIT100081 TSU100084'))
  • re.compile(pattern, flags=0):将正则表达式的字符串形式编译成正则表达式对象
pat = re.compile(r'[1-9]\d{5}')
rst = pat.search('BIT 100081')
match对象
match对象的属性
属性说明
.string待匹配的文本
.re匹配时使用的pattern对象(正则表达式)
.pos正则表达式搜索文本的开始位置
.endpos正则表达式搜索文本的结束位置
match对象的方法
方法说明
.group(0)获得匹配后的字符串
.start()匹配字符串在原始字符串的开始位置
.end()匹配字符串在原始字符串的结束位置
.span()返回(.start(),.end())(元组类型)
Re库的贪婪匹配和最小匹配

Re库默认采用贪婪匹配,即输出匹配最长的子串

match = re.search(r'PY.*N', 'PYNTHON')
最小匹配
操作符说明
*?前一个字符0次或无限次扩展,最小匹配
+?前一个字符1次或无限次扩展,最小匹配
??前一个字符0次或1次扩展,最小匹配
{m,n}?扩展前一个字符m至n次,最小匹配
match = re.search(r'PY.*?N', 'PYNTHON')

实例1:大学排名定向爬虫

import requests
import bs4
from bs4 import BeautifulSoup

def getHTMLText(url):
    try:
        r = requests.get(url, timeout = 30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""

def fillUnivList(ulist, html):
    soup = BeautifulSoup(html, "html.parser")
    for tr in soup.find('tbody').children:  #在tbody标签中遍历tr标签
        if isinstance(tr, bs4.element.Tag): #过滤tr标签
            tds = tr('td')  #将需要的td标签放入列表中
            ulist.append([tds[0].string, tds[1].string, tds[3].string])


def printUnivList(ulist, num):
    tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
    print(tplt.format("排名", "学校名称", "总分", chr(12288)))
    for i in range(num):
        u = ulist[i]
        print(tplt.format(u[0], u[1], u[2], chr(12288)))
    print("Suc" + str(num))

def main():
    uinfo = []
    url = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2019.html'
    html = getHTMLText(url)
    fillUnivList(uinfo, html)
    printUnivList(uinfo, 20)
main()

实例2:淘宝商品信息定向爬虫

  1. 提交商品搜索请求,循环获取页面
  2. 对于每个页面,提取商品名称和价格信息
  3. 输出

需要替换http request header来欺骗浏览器实现登录
参考

import requests
import re

def getHTMLText(url):
    try:
        kv = {'user-agent': 'Mozilla/5.0', 'cookie': 'cna=zIRRFl/4eTsCAXJXhTgb4lGt; t=5160a85424fe174c6483c21b457a7924; UM_distinctid=16e676c7723458-096acb70b9ae84-7711a3e-144000-16e676c772420e; thw=cn; miid=637631782000795542; hng=CN%7Czh-CN%7CCNY%7C156; tracknick=%5Cu5BFB%5Cu627E%5Cu5927%5Cu6D77%5Cu7684%5Cu8FB9%5Cu9645; tg=0; enc=xfF4HAm8jO%2BUszxmV8ICy3Q30oEGEP2RneojvYIePy4qijus9ou9uroNbTbO7LawB7PG6GFSa30ENlpKC7s2qg%3D%3D; lgc=%5Cu5BFB%5Cu627E%5Cu5927%5Cu6D77%5Cu7684%5Cu8FB9%5Cu9645; mt=ci=-1_0; v=0; cookie2=1c39d4f8be33f0c008c9ba12cc683f51; _tb_token_=eb58e3914637b; _samesite_flag_=true; dnk=%5Cu5BFB%5Cu627E%5Cu5927%5Cu6D77%5Cu7684%5Cu8FB9%5Cu9645; _mw_us_time_=1581257284309; unb=3298721164; uc1=cookie14=UoTUO8IXvg05xA%3D%3D&cookie15=WqG3DMC9VAQiUQ%3D%3D&pas=0&cookie16=UIHiLt3xCS3yM2h4eKHS9lpEOw%3D%3D&tag=8&existShop=false&cookie21=Vq8l%2BKCLjA%2Bl&lng=zh_CN; uc3=lg2=WqG3DMC9VAQiUQ%3D%3D&id2=UNJYTSb8qyy%2BXQ%3D%3D&nk2=sr8Vs0VugPzEVg7lNik%3D&vt3=F8dBxdsanYORhSwLwS8%3D; csg=f90609f8; cookie17=UNJYTSb8qyy%2BXQ%3D%3D; skt=2c23f554dc07c90e; existShop=MTU4MTI1NzI4OA%3D%3D; uc4=id4=0%40UgXf7eZnM5SB1%2B%2BDWqIn9B4aoaDK&nk4=0%40sLdrDpuShvdSuCTc9Ehn21Dl2KPIMwvs4g%3D%3D; _cc_=U%2BGCWk%2F7og%3D%3D; _l_g_=Ug%3D%3D; sg=%E9%99%854e; _nk_=%5Cu5BFB%5Cu627E%5Cu5927%5Cu6D77%5Cu7684%5Cu8FB9%5Cu9645; cookie1=W8DZrI54q0OdcLVx7R3%2BVI4N%2FXEE2FhVBLYSKtrKtE8%3D; isg=BDw8S-C2To8AgXlfYamMSzRUDdruNeBfi2nGQxa9SCcK4dxrPkWw77JTwQmZshi3; l=cBrDvrCcqejNAMBEBOCanurza77OSIRYYuPzaNbMi_5Qy6T_qO7OoSe2NF96VjWd998B4Tn8Nrv9-etkZK066bIpXUJ1.'}
        r = requests.get(url, timeout=30, headers=kv)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        #print(r.text)
        return r.text
    except:
        return ""

def parsePage(ilt, html):
    try:
        plt = re.findall(r'\"view_price\"\:\"[\d\.]*\"', html)
        tlt = re.findall(r'\"raw_title\"\:\".*?\"', html)
        for i in range(len(plt)):
            price = eval(plt[i].split(':')[1])  #eval:去掉双引号或单引号
            title = eval(tlt[i].split(':')[1])
            ilt.append([price, title])
    except:
        print("")

def printGoodList(ilt):
    tplt = "{:4}\t{:8}\t{:16}"
    print(tplt.format("序号", "价格", "商品名称"))
    count = 0
    for g in ilt:
        count = count+1
        print(tplt.format(count, g[0], g[1]))

def main():
    goods = '书包'
    depth = 3
    start_url = 'https://s.taobao.com/search?q=' + goods
    infoList = []
    for i in range(depth):
        try:
            url = start_url + '&s=' + str(44*i)
            html = getHTMLText(url)
            parsePage(infoList, html)
        except:
            continue
    printGoodList(infoList)

main()
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值