来一套爬虫

什么是爬虫

一个用来完成网站请求和提取网站中的数据的自动化的程序。

一个
可以
完成网站请求
提取数据
的自动化
的程序

怎么爬

1 发起请求:通过HTTP库向目标站点发起请求,发送request。
2 获取响应内容:得到一个包含诸多内容的response。
3 解析响应内容:对得到的response进行解析。
4 保存爬取内容

那我爬什么呢

可见即可爬
爬点小电影?
爬点小图片?
爬点嘿嘿嘿小说?
……

解析方式

爬取下来的网页数据该如何处理?
正则
xpath
json
BeautifulSoup
PyQuery
……

别说了 爬就完事了

python如何访问互联网?

需要用到urllib(这是一个包(package),包含了网页地址(URL)和Library(lib),包含了四个模块:request、error、parse、robotparser)

URL = 协议(protocol:http、https、ftp……) + 域名(hostname) +路径(path)

GET请求

import urllib.request   #调用urllib包中的request模块
baidu = urllib.request.urlopen('https://www.baidu.com')  #获取百度
html = baidu.read().decode('utf-8')   #read 读取百度   decode编码
print(html)  #打印
-->   '太长啦,我就只复制一部分结果'
<!DOCTYPE html>
<!--STATUS OK-->




POST请求

import urlli.parse
import urllib.request
temp = bytes(urllib.parse.urlencode({'word' : 'hello'}),encoding = 'utf-8')
res = urllib.request.urlopen('http://httpbin.org/post' , data=data)
print(res)

-->
b'{\n  "args": {}, \n  "data": "", \n  "files": {}, \n  "form": {\n    "word": "hello"\n  }, \n  "headers": {\n    "Accept-Encoding": "identity", \n    "Content-Length": "10", \n    "Content-Type": "application/x-www-form-urlencoded", \n    "Host": "httpbin.org", \n    "User-Agent": "Python-urllib/3.7"\n  }, \n  "json": null, \n  "origin": "223.12.174.68, 223.12.174.68", \n  "url": "https://httpbin.org/post"\n}\n'

Handler ProxyHandler 代理

代理干啥用的?
兄弟别问了好吗,你翻墙不知道偷偷摸摸干点啥的时候用的不就是。。。

import urllib.request
import urllib.parse
#创建handler
proxy_handler = urllib.request.ProxyHandler({'http':'http://211.147.239.101:57281','https':'https://211.147.239.101:57281'})
#创建opener
opener = urllib.request.build_opener(proxy_handler)
#创建headers
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'}
url = 'http://www.baidu.com'
#Request可以添加请求头等信息
request = urllib.request.Request(url,headers = headers)
res = opener.open(resquest)
print(res.read())
-->
'别问为什么没结果,因为失败了23333,会提示由于目标计算机积极拒绝,无法连接'

cookie

2333
我朋友家有只黑色小泰迪就叫cookie 贼亲~
cookie其实就是入场通行证,一人一证,持证通过
爬虫中主要是用来维持登录状态的一个属性

import urllib.request
import http.cookiejar
#申明cookiejar对象
cookie = http.cookiejar.CookieJar()
#使用handler处理cookie
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
#打印出name和value
for i in cookie:
	print(i.name + '=' + i.value)

-->
BAIDUID=CB2FDE6A308D8C02DFC2AA33E27F4D93:FG=1
BIDUPSID=CB2FDE6A308D8C02DFC2AA33E27F4D93
H_PS_PSSID=28884_1431_28777_21087_28768_28723_28838_28585_20718
PSTM=1555998931
delPer=0
BDSVRTM=0
BD_HOME=0

cookie保存成文本文件 前面基本一样 最后需要用cookie.save

import http.cookiejar
import urllib.request
filename = 'cookie.txt'
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True,ignore_expires=True)

-->
'保存好的文件内容:'
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file!  Do not edit.

.baidu.com	TRUE	/	FALSE	3703484264	BAIDUID	C27D5E631BA7EF490324B73BA07BA8EC:FG=1
.baidu.com	TRUE	/	FALSE	3703484264	BIDUPSID	C27D5E631BA7EF490324B73BA07BA8EC
.baidu.com	TRUE	/	FALSE		H_PS_PSSID	1467_28777_21083_28775_28721_28833_28584_26350_28604
.baidu.com	TRUE	/	FALSE	3703484264	PSTM	1556000617
.baidu.com	TRUE	/	FALSE		delPer	0
www.baidu.com	FALSE	/	FALSE		BDSVRTM	0
www.baidu.com	FALSE	/	FALSE		BD_HOME	0

读取cookie

import http.cookiejar
import urllib.request
cookie = http.cookiejarMozillaCookieJar()
#cookie = http.cookiejar.LWPCookieJar()    另一种保存方式
cookie.load('cookie.txt',ignore_discard=True,ignore_expires=True)
handle = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))

-->'复制部分结果'
<html>
<head>
    
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
	<meta content="always" name="referrer">
    <meta name="theme-color" content="#2932e1">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
    <link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml" title="百度搜索" />
    <link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg">
	
	
	<link rel="dns-prefetch" href="//s1.bdstatic.com"/>
	<link rel="dns-prefetch" href="//t1.baidu.com"/>
	<link rel="dns-prefetch" href="//t2.baidu.com"/>
	<link rel="dns-prefetch" href="//t3.baidu.com"/>
	<link rel="dns-prefetch" href="//t10.baidu.com"/>
	<link rel="dns-prefetch" href="//t11.baidu.com"/>
	<link rel="dns-prefetch" href="//t12.baidu.com"/>
	<link rel="dns-prefetch" href="//b1.bdstatic.com"/>
    
    <title>百度一下,你就知道</title>
    

URL解析

from urllib.parse import urlparse

urlparse将输入的url进行自动解析分类

from urllib.parse import urlparse
temp = urlparse('https://www.baidu.com/s?ie=UTF-8&wd=baidu')
print(temp)

-->
ParseResult(scheme='https', netloc='www.baidu.com', path='/s', params='', query='ie=UTF-8&wd=baidu', fragment='')

urlunparse将代码完成拼接,逆向完成urlparse过程

from urllib.parse import urlunparse
temp = ['https','www.baidu.com','/s','','ie=UTF-8&wd=baidu','']
print(urlunparse(temp))

-->
https://www.baidu.com/s?ie=UTF-8&wd=baidu

================================================================

来来来 撸一只猫猫

http://placekitten.com
代码撸起来:

import urllib.request
cat = urllib.request.urlopen('http://placekitten.com/200/300')
cat_img = cat.read()

with open('cat_200_300.jpg','wb') as f:
    f.write(cat_img)

然后就可以撸到一只猫猫啦比如说这样↓↓↓↓↓↓↓↓
在这里插入图片描述
除了cat.read()方法之外,还有其他方法了解一下

cat.geturl()   #得到访问地址
-->
'http://placekitten.com/200/300'

cat.info()     #得到http的文件对象信息
-->
<http.client.HTTPMessage object at 0x0000000002F00198>
 
cat.getcode    #正常响应
-->
200

cat.status		#正常响应
-->
200

cat.getheaders()		#请求头
-->
[('Date', 'Mon, 22 Apr 2019 12:37:22 GMT'), ('Content-Type', 'image/jpeg'), ('Transfer-Encoding', 'chunked'), ('Connection', 'close'), ('Set-Cookie', '__cfduid=d4b21eb66a83006fe512f66469a66d6cd1555936642; expires=Tue, 21-Apr-20 12:37:22 GMT; path=/; domain=.placekitten.com; HttpOnly'), ('Access-Control-Allow-Origin', '*'), ('Cache-Control', 'public, max-age=86400'), ('Expires', 'Tue, 23 Apr 2019 12:37:22 GMT'), ('CF-Cache-Status', 'HIT'), ('Vary', 'Accept-Encoding'), ('Server', 'cloudflare'), ('CF-RAY', '4cb7a6106d069756-FRA')]

================================================================

requests库

安装

pip install requests

***requests***库的主要方法

requests.request()      #构造请求
requests.get()			#获取http中的“主要方法“
requests.head()			#获取http中的头部信息  r.header展示头部信息
requests.post()			#向http提交post请求,url位置后附加新的数据
requests.put()			#向http提交put请求,向url位置存储一个资源覆盖原有资源
requests.patch()		#向http提交局部修改,更新局部url位置的资源
requests.delete()		#提交删除请求,删除局部url位置资源

***response***对象的属性

r = request.get('http://www.*****.com')		#response = requests.get(url)		url = http://www.*****.com		请求url中的服务器请求资源
r.status_code 								#如果返回值=200则正常否则无法正常运行
r.text 										#url返回的字符串
r.encoding									#编码方式
r.apprent_encoding							#备选编码方式
r.content									#响应内容的二进制形式
r.json										#json
r.cookies									#cookies

影藏user agent

r.request.headers			#查看header中的user agent

{'User-Agent': 'python-requests/2.21.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}		#结果

header = {‘user-agaent’:'Mozilla/5.0'}			#伪装user-agent
r = request.get(url,headers = header)

{'user-agent': 'Mozilla/5.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}			#结果

================================================================
百度寻找女神苍井空

import requests
url = 'http://www.baidu.com/s'
kw = {'wd':'苍井空'}
r = requests.get(url, params = kw)
r.status_code
r.request.url
len(r.text)

================================================================
ip地址查询

import requests
ip = str(input('请输入查询的ip地址:'))		#应该加一个判断输入数据的类型
url ='http://m.ip138.com/ip.asp?ip='		#但是我懒。。
r = requests.get(url+ip)
print(r.text[-500:])
========================================================================
import requests								#讲道理  应该这样写
ip = str(input('请输入查询的ip地址:'))		#但是我就是不加判断语句
url ='http://m.ip138.com/ip.asp?ip='		#2333
try:
    r = requests.get(url+ip)
    r.raise_for_status()
    r.ending = r.apparent_encoding
    print(r.text[-500:])
except:
    print('失败')

================================================================

BeautifulSoup库

解析器:
html:bs4库
lxml:lxml库
xml:lxml库
html5lib:html5lib库

'安装:'   pip install lxml/html5lib
'调用:'   BeautifulSoup(***,'html.parse'/'lxml'/'xml'/'html5lib')    '***为目标代码'

基本元素:
Tag:开头 <>, 结尾</>
Name: 标签的名字 ,

,p就是名字 ;.name
Attribute:.attrs
NavigableString:.string
Comment:注释

BS的遍历方法

下行遍历
.contents:子节点列表,的儿子节点存入列表
.children:子节点的迭代类型,用于循环遍历儿子节点
.descendants:子孙节点的迭代类型,包含所有子孙节点,循环遍历

上行遍历
.parent:节点的父亲标签
.parents:节点先辈标签的迭代类型,用于循环遍历先辈节点

平行遍历
.next_sibling:返回html文本顺序的下一个平行节点标签
.previous_sibling:返回html文本顺序的上一个平行节点标签
.next_siblings:返回html文本顺序的后续所有平行节点标签
.previous_siblings:返回html文本顺序的前续所有平行节点标签

美丽汤的用法

html ='''
<html>
<head> <meta http-equiv="content-type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta content="always" name="referrer">
    <meta name="theme-color" content="#2932e1">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml" title="百度搜索" />
<link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg">
<link rel="dns-prefetch" href="//s1.bdstatic.com"/>
	<link rel="dns-prefetch" href="//t1.baidu.com"/><link rel="dns-prefetch" href="//t2.baidu.com"/>
	<link rel="dns-prefetch" href="//t3.baidu.com"/>
	<link rel="dns-prefetch" href="//t10.baidu.com"/>
	<link rel="dns-prefetch" href="//t11.baidu.com"/>
	<link rel="dns-prefetch" href="//t12.baidu.com"/>
	<link rel="dns-prefetch" href="//b1.bdstatic.com"/>
    <title>百度一下,你就知道
    '''
    #并不规范的格式
from bs4 import BeautifulSoup
soup = BeautifulSoup(html,'lxml')
print(soup.prettify())		#整理标签
print(soup.title.string)	#打印title中的str
print(soup.meta['content']) #打印meta标签中的content属性

-->
<html>
 <head>
  <meta content="text/html;charset=utf-8" http-equiv="content-type"/>
  <meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
  <meta content="always" name="referrer"/>
  <meta content="#2932e1" name="theme-color"/>
  <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon"/>
  <link href="/content-search.xml" rel="search" title="百度搜索" type="application/opensearchdescription+xml"/>
  <link href="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg" mask="" rel="icon" sizes="any"/>
  <link href="//s1.bdstatic.com" rel="dns-prefetch"/>
  <link href="//t1.baidu.com" rel="dns-prefetch"/>
  <link href="//t2.baidu.com" rel="dns-prefetch"/>
  <link href="//t3.baidu.com" rel="dns-prefetch"/>
  <link href="//t10.baidu.com" rel="dns-prefetch"/>
  <link href="//t11.baidu.com" rel="dns-prefetch"/>
  <link href="//t12.baidu.com" rel="dns-prefetch"/>
  <link href="//b1.bdstatic.com" rel="dns-prefetch"/>
  <title>
   百度一下,你就知道
  </title>
 </head>
</html>				#整理完成

百度一下,你就知道	#title标签的内容

text/html;charset=utf-8  #meta标签下的content属性内容

and

'find_all(name,attrs,recursive,**kwargs)'    返回所有匹配
'find(name,attrs,recursive,**kwargs)' 		 返回一个匹配
name:标签名    字符串类型  
print(soup.find_all('meta'))
-->
[<meta content="text/html;charset=utf-8" http-equiv="content-type"/>, <meta content="IE=Edge" http-equiv="X-UA-Compatible"/>, <meta content="always" name="referrer"/>, <meta content="#2932e1" name="theme-color"/>]

arrts:元素    字典类型
print(soup.find_all('http-equiv':"content-type"))  #attrs中存入字典类型的寻找目标的属性
print(soup.find_all(content="IE=Edge"))
-->
[<meta content="text/html;charset=utf-8" http-equiv="content-type"/>]  #获取标签
[<meta content="IE=Edge" http-equiv="X-UA-Compatible"/>]

text:标签内容
print(soup.find_all(text='内容'))     #内容的查找   返回内容

美丽汤中的CSS选择器

嵌套选择

HTML = '''
<div class="qrcodeCon">
	<div id="qrcode">
		<div class="qrcode-item qrcode-item-1">
			<div class="qrcode-img"></div>
			<div class="qrcode-text">
				<p><b>百度</b></p>
			</div>
		</div>
'''
soup = BeautifulSoup(HTML,'lxml')
'class=“巴拉巴拉”  提取class属性的时候只需要   “.巴拉巴拉”就可以'
print(soup.select('.qrcode-text'))			#提取class="qrcode-text"下的标签
-->	
[<div class="qrcode-text">					#通过class="qrcode-text"属性查找
<p><b>百度</b></p>
</div>]

print(soup.select('div p'))			#提取div标签下的p标签   用空格隔开
-->
[<p><b>百度</b></p>]				#通过div下的p标签的标签查找

'id="巴拉巴拉"   提取id属性的时候只需要      “#巴拉巴拉”就可以'
print(soup.select('#qrcode .qrcode-img'))	# 用#查找id下的以class开头的标签   用空格隔开
-->
[<div class="qrcode-img"></div>]

获取属性 [‘属性名称’]

print(soup.select('div')[0]['class'])   #div标签下的class属性
-->
['qrcodeCon']

获取文本 get_text()

print(soup.select('p')[0].get_text())		#打印P标签下的文本
-->
百度

================================================================

主C位:正则表达式

你懂得~

import re    #调用re库  燥起来

常用的元字符: . ^ $ * + ? | []

. 通配符 可匹配所有除去\n的一个字符(使用re.S可匹配到\n)
EX = 'py\nthon\nthon123'
'.'通配符 :
r1 = re.findall('.',EX)
print('r1',r1) 				'没有搜索到\n的结果'
-->r1  ['p', 'y', 't', 'h', 'o', 'n', 't', 'h', 'o', 'n', '1', '2', '3']
r2 = re.findall('.',EX,re.S)
print('r2',r2)					'搜索到了\n的结果'
-->r2 ['p', 'y', '\n', 't', 'h', 'o', 'n', '\n', 't', 'h', 'o', 'n', '1', '2', '3']
^ 脱字符 从待检查位置开始,用^脱字符后的内容进行匹配检查,若待检查开始位置不匹配则返回空,若待检查开始位置匹配,则返回一个结果(re.M可搜索多个结果);还有一种取反的用法
"^"脱字符:					
EX = 'woshinibaba\nbaba'
r1 = re.findall('^ba',EX)
print('r1',r1)
-->r1 []				'返回结果为空,因为woshinibaba开头和ba不匹配'
EX1 = 'babashiwo\nbabanihao'
r2 = re.findall('^ba',EX1)	
print('r2',r2)		
-->r2 ['ba']						'只搜索了第一行的开头,返回了一个结果'
r3 = re.findall('ba',EX1,re.S)
print('r3',r3)
-->r3 ['ba', 'ba', 'ba', 'ba']		'不哔哔了,这样总看的出来吧'
r4 = re.findall('[^ba]',EX)
-->['w', 'o', 's', 'h', 'i', 'n', 'i', '\n']	'取反'
$ 搜索待匹配项的结尾(re.M可以搜索多行后返回)
'$':
EX = '2019.3.24'
r1 = re.findall('24$',EX)
print('r1',r1)
-->r1 ['24']
're.M和上面类似,算了还是写一遍吧,我真踏马好'
EX1 = 'wakaka\nkaka'
r2 = re.findall('ka$',EX1,re.M)
print('r2',r2)
-->r2 ['ka', 'ka']			'第一行搜索出一个ka返回,第二行搜索一个ka返回'
* + ? 依次匹配前一个字符的0或者无限次、1或者无限次、0或者1次
'好累啊  不想写栗子了呀'
EX = 'what,whaat,whaaaaat'
r1 = re.findall('a*',EX)
-->r1 ['', '', 'a', '', '', '', '', 'aa', '', '', '', '', 'aaaaa', '', '']   
		'what,whaat,whaaaaat中遇到a的0~无限次就返回,返回''空的值是说明位置是a的0次'
r2 = re.findall('a+',EX)
-->r2 ['a', 'aa', 'aaaaa']		'只有遇到a的1~n次时候返回,其他时候不返回'
r3 = re.findall('a?',EX)				'啥也返回'
-->r3 ['', '', 'a', '', '', '', '', 'a', 'a', '', '', '', '', 'a', 'a', 'a', 'a', 'a', '', ''] 			
						往后面看还有最小匹配操作符
{m,n} /{m} 返回出现m~n次/m次的结果
							这个很简单不举例子了哈
或,与或非里面的或;就是说丨两边的任一表达式得到匹配就会返回匹配项
EX = 'woshinibaba'
r1 = re.findall('w|b',EX)
print('r1',r1)
-->r1 ['w', 'b', 'b']
[abc] /[a-z] a/b/c中的任一字符/a~z任一字符
							这还举个毛栗子啊

re库的主要功能函数

函数 功能
re.search(pattern,string,flags=0) 简单说就是在一串字符串(string)中搜索和正则表达式(pattern)一样的第一个位置,返回一个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); repl:替换匹配字符串的字符串,count:匹配的最大替换次数 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
pattern:正则表达式;string:待匹配的字符串;flags:正则表达式使用时候的一些控制标记;maxsplit:最大分割数,剩余部分作为最后一个元素 关于flags的常用标记:re.I:忽略正则表达式的大小写;re.M:匹配每行的开始部分;re.S:匹配所有字符

等价用法;面向对象编译:

'栗子'
'大大的栗子'
pat = re.compile('[0-9]\d{5}')		
rst = pat.search('我是栗子111111')

match对象

match对象的属性 说明
.string 返回待匹配的文本
.re 返回匹配时使用的正则表达式
.pos 返回正则表达式搜索文本的开始位置
.endpos 返回正则表达式搜索文本的结束位置
match的方法 说明
.group(0) 获得匹配后的第一个字符串
.start() 匹配字符串在原始字符串的开始位置
.end() 匹配字符串在原始字符串的结束位置
.span() 返回(.start(),.end())

最小匹配操作符

一般都是默认最长匹配。

'举个栗子'
match = re.search(r'WTF.*K','WTFAKBKCKDK')  #'WTF.*K' = WTF开头+中间随机+K结尾
match.group(0)
-->'WTFAKBKCKDK'    #输出最长的字符串
操作符 说明
*? 前一个字符0次或者无限次扩展,最小匹配
+? 前一个字符1次或者无限次扩展,最小匹配
?? 前一个字符0次或者一次扩展,最小匹配
{m,n}? 扩展前一个字符m至n次(含n),最小匹配

正则爬取豆瓣读书列表

import re
import requests
url = 'https://book.douban.com/'
content = requests.get(url).text
pattern = re.compile('<li.*?cover.*?href="(.*?)".*?title"(.*?)".*?"author">(.*?)</div>.*?<span.*?"year">(.*?)<span>.*?</li>',re.S)
result = re.findall(pattern,content)
for i in result:
    url,name,author,date = i
    print(url,name,author,date)
    

猜你喜欢

转载自blog.csdn.net/dh0805dh/article/details/88668572