一、response响应参数
1、response六个参数
response.read().decode().encode() # decode()解码 encode()编码
response.readline()#读取一行
response.readlines()# 读取所有,是二进制
response.geturl()#请求的路由
response.getheaders()#获取响应头
response.getcode()#200 响应状态码
2、代码实现
import urllib.requesturl='http://www.baidu.com/'response=urllib.request.urlopen(url=url)#.decode()解码 encode()编码 read()读取全部内容,游标后移动到网页最后 所以后面没有
# print (response.read().decode().encode())
print (response.read().decode())#读取一行
print (response.readline())# 读取所有,是二进制
print(response.readlines())#路由
print(response.geturl())#http://www.baidu.com/#获取响应头
print(response.getheaders())
#[('Bdpagetype', '1'), ('Bdqid', '0x820558ba00024ee3'), ('Cache-Control', 'private'), ('Content-Type', 'text/html'), ('Cxy_all', 'baidu+0c2a38edaddb678d40838303d1f94212'), ('Date', 'Mon, 22 Oct 2018 06:33:29 GMT'), ('Expires', 'Mon, 22 Oct 2018 06:33:09 GMT'), ('P3p', 'CP=" OTI DSP COR IVA OUR IND COM "'), ('Server', 'BWS/1.1'), ('Set-Cookie', 'BAIDUID=2EF25B13DB45A9EEF4DD58F5E957A73A:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com'), ('Set-Cookie', 'BIDUPSID=2EF25B13DB45A9EEF4DD58F5E957A73A; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com'), ('Set-Cookie', 'PSTM=1540190009; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com'), ('Set-Cookie', 'delPer=0; path=/; domain=.baidu.com'), ('Set-Cookie', 'BDSVRTM=0; path=/'), ('Set-Cookie', 'BD_HOME=0; path=/'), ('Set-Cookie', 'H_PS_PSSID=1458_21094_26350_22075; path=/; domain=.baidu.com'), ('Vary', 'Accept-Encoding'), ('X-Ua-Compatible', 'IE=Edge,chrome=1'), ('Connection', 'close'), ('Transfer-Encoding', 'chunked')]#200 状态码
print(response.getcode())
二、urlretrieve下载文件
1、urlretrieve参数
url = html_url = 'https://www.baidu.com/' #(下载的文件的网址)
filename = filenames = r"E:\Knowledge\爬虫\files\baidu1.html" #(存放下载文件的路径以及名称)
2、代码实现
#本地存储 网页下载 视频下载 图片下载
import urllib.request
def html_download():html_url='https://www.baidu.com/'filenames=r"E:\Project_python\python_directory\Knowledge\爬虫\files\baidu1.html"urllib.request.urlretrieve(url=html_url,filename=filenames)def picture_download():picture_url = 'http://img2.ali213.net/picfile/News/2018/10/22/2018102271311324.jpg'filenames = r"E:\Project_python\python_directory\Knowledge\爬虫\files\RNG.png"urllib.request.urlretrieve(url=picture_url, filename=filenames)def movie_download():movie_url='http://v11-tt.ixigua.com/9afa9be76829c9c86efc5ed457b5e40b/5bcdd016/video/m/2206a2ae6c28c2044c29a8a93a76e7ad720115bc34400002caef5bf2788/'filenames= r"E:\Project_python\python_directory\Knowledge\爬虫\files\回家.MP4"urllib.request.urlretrieve(url=movie_url,filename=filenames)if __name__=="__main__":#html_download()#picture_download()#movie_download()
三、Get请求路由参数
1、单个参数
1、方法
urllib.request.quote(name) #name为字符串
2、代码实现
def http_get_quote():get_url = 'http://www.baidu.com/s?wd='name = input('输入关键字:')gjz=urllib.request.quote(name)#单个关键字处理-也就是格式化处理,符合路由urls=get_url+gjzresponse=urllib.request.urlopen(url=urls)print(response.read().decode())
2、多个参数
1、方法
urllib.parse.urlencode(data) #多关键字,将其整理为字典形式(data),通过urlencode路由编码
2、代码实现
def http_get_urlencode():get_url = 'http://www.baidu.com/s?'name = input('输入关键字:')data = {'wd': name,}urldata = urllib.parse.urlencode(data)#多关键字,将其整理为字典形式,通过urlencode路由编码urls = get_url + urldataprint(urls)response = urllib.request.urlopen(url=urls)print(response.read().decode())
四、Get AND Post
1、Get请求
def http_get():get_url = 'http://www.baidu.com/s?'name = input('输入关键字:')data = {'wd': name,}data = urllib.parse.urlencode(data)url = get_url + dataheaders = {"User-Agnet": "Mozilla/5.0 (Linux; U; Android 4.0.3; zh-cn; M032 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"}request = urllib.request.Request(url=url, headers=headers)response = urllib.request.urlopen(request)print(response.read().decode('utf-8'))
2、Post请求
def http_post():post_url="https://fanyi.baidu.com/sug"keyword=input("输入搜索的单词:")data={'kw': keyword}#相较于get需要在字典的路由编码中添加编码方式'utf-8'data=urllib.parse.urlencode(data).encode('utf-8')headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}#get是将参数放在路由请求中,而post是现代form表单,属于不可见request = urllib.request.Request(url=post_url, headers=headers, data=data, )response = urllib.request.urlopen(request, timeout=0.5)except Exception as re:print("请求超时")print(response.read().decode("utf-8"))
五、请求方式的定制
1、代码实现
import urllib.request,urllib.parsedef headers_add():url = 'http://www.baidu.com/s?'data = {'wd': '韩红','age': 25}urls = url + urllib.parse.urlencode(data)headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',}#请求方式的定值,也就是设置单独的request,不同的请求头、是get还是postrequest = urllib.request.Request(url=urls, headers=headers)response = urllib.request.urlopen(request)print(response.read().decode())
六、Get方式获取Ajax
1、代码实现
获取豆瓣电影的数据,通过定制的get请求,模拟浏览器通过ajax向服务器发送请求,获取json数据
import urllib.request
import urllib.parsedef Ajax_request():page=int(input("请输入页码:"))url_ajax='https://movie.douban.com/j/chart/top_list?'headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3554.0 Safari/537.36',}pagenumber=(page-1)*20data={ #通过观察请求页面的request的参数,形成下面的参数数据字典'type':'24','interval_id':'100:90','action':'爱情','start':pagenumber,'limit':'20',}data=urllib.parse.urlencode(data)urls=url_ajax+datarequest=urllib.request.Request(url=urls,headers=headers)respone=urllib.request.urlopen(request)context=respone.read().decode('utf-8')with open(r'E:\Project_python\……\douban.json','w',encoding='utf-8') as fp:fp.write(context)
七、简单封装
1、豆瓣、页面、封装
import urllib.request
import urllib.parsedef create_request(type,page):#定制请求方式#https://movie.douban.com/tag/动作?start=60&type=Turl_post='https://movie.douban.com/tag/'headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3554.0 Safari/537.36',}page=(page-1)*20data={"start":page,'type': 'T',}type=urllib.request.quote(type)data=urllib.parse.urlencode(data)url=url_post+type+'?'+dataprint(url)request=urllib.request.Request(url=url,headers=headers)return requestdef save_context(request):#发送请求,接收响应并返回,返回的是页面源码(字符串形式)response=urllib.request.urlopen(request)context=response.read().decode('utf-8')return contextdef down_load(page,context):#下载并将页面保存到指定的页面url=r'E:\Project_python\python_directory\Knowledge\爬虫\files\douban_fengzhuang'filename=url + '\douban_'+str(page)+'.html'with open(filename,'w',encoding='utf-8')as fp:fp.write(context)if __name__=="__main__":type=input("类型:")startpage=int(input("开始页:"))endpage=int(input("结束页:"))for page in range(startpage,endpage+1):request=create_request(type,page)context=save_context(request)down_load(page, context)
2、KFC、Json、封装
import urllib.request
import urllib.parsedef create_request(cname,page):post_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}data = {'cname':cname,'pid':'','pageIndex':page,'pageSize':'10'}data = urllib.parse.urlencode(data).encode('utf-8')request = urllib.request.Request(url = post_url,headers=headers,data=data)return requestdef save_content(request):response = urllib.request.urlopen(request)content = response.read()#当不跟着写decode()解码函数时候,将返回的是二进制,下面要写为"wb"return contentdef down_load(content,page):# 如果响应的数据类型是二进制 那么写入文件就需要使用wb的模式# 使用wb模式的时候 是不能指定编码的url = r'E:\Project_python\python_directory\Knowledge\爬虫\files\douban_fengzhuang'filename = url + '\KFC_' + str(page) + '.html'with open(filename, 'wb')as fp:fp.write(content)if __name__ == '__main__':cname = input('请输入你要查询的地点')start_page = int(input('请输入起始页码'))end_page = int(input('请输入结束页码'))for page in range(start_page,end_page+1):request = create_request(cname,page)content = save_content(request)down_load(content,page)
八、代理吃和快代理
1、代理池
import urllib.request
import randomdef agent():url = 'https://www.baidu.com/s?wd=ip'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}request = urllib.request.Request(url=url, headers=headers)# 代理池 实际就是找到一些好用的代理ip 然后存储到列表中# 进行随机选择proxylist = [{'https': '114.116.10.21:3128'},{'https': '120.92.74.189:3128'},{'https': '113.200.56.13:8010'},]proxies = random.choice(proxylist)# ProxyHandler中的参数名字固定为proxies 没有其他参数handler = urllib.request.ProxyHandler(proxies=proxies)opener = urllib.request.build_opener(handler)response = opener.open(request)content = response.read().decode('utf-8')with open(r'E:\Project_python\python_directory\Knowledge\爬虫\files\zaza\ip1.html', 'w', encoding='utf-8')as fp:fp.write(content)
2、快代理
import urllib.request
#也就网上购买代理ip,从而隐藏自身ip信息。
def Fast_agent():#网站购买的高匿ip,得到的IP地址以及接口号,(无效)url = 'http://kps.kdlapi.com/api/getkps/?orderid=914028249605725&num=1&pt=1&sep=1'response = urllib.request.urlopen(url=url)ip1 = response.read().decode('utf-8')print(ip1)#ip1='114.116.10.21:3128'handler = urllib.request.ProxyHandler(proxies={'https': ip1})opener = urllib.request.build_opener(handler)url1 = 'https://www.baidu.com/s?wd=ip'headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36' }request = urllib.request.Request(url=url1, headers=headers)response1 = opener.open(request)content1 = response1.read().decode('utf-8')with open('ip2.html', 'w', encoding='utf-8')as fp:fp.write(content1)
九、cookiejar—全书网
1、代码实现
#在未登录的情况下,进入全书网的个人藏书架界面,思路:先模仿登录请求,然后携带cookie访问藏书架
#如何抓取登陆接口,
import urllib.request
import urllib.parse
import http.cookiejarpost_url = 'http://www.quanshuwang.com/login.php?do=submit'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
}
data = {'username': 'action','password': 'action','action': 'login',
}
data = urllib.parse.urlencode(data).encode('gbk')request = urllib.request.Request(url=post_url,headers=headers,data=data)#创建cookiejar对象
ck = http.cookiejar.CookieJar()#把cookiejar对象当作参数传给HTTPCookieProcessor
hander = urllib.request.HTTPCookieProcessor(ck)#获取opener对象
opener = urllib.request.build_opener(hander)#浏览器向服务器发送请求 并且将cookie信息保存到了opener中
#下次通过operer对象访问服务器的时候 会携带者该cookie
response = opener.open(request)# print(response.read().decode('gbk'))
get_url = 'http://www.quanshuwang.com/modules/article/bookcase.php'request1 = urllib.request.Request(url=get_url,headers=headers)# response1 = urllib.request.urlopen(request1)
response1 = opener.open(request1)
print(response1.read().decode('gbk'))
壹、爬虫进阶(聚焦爬虫)
十、XPath:XML路径语言
1、简介
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。
XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初XPath的提出的初衷是将其作为一个通用的、介于XPointer与XSL间的语法模型。但是XPath很快的被开发者采用来当作小型查询语言。
2、xpath语法
表达式 / 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。div[@id="mat"] #谓词(属性)查询(id唯一,class不唯一)
div[contains(@id, "he")] #模糊查询id属性包含he
div[starts-with(@id, "he")] #模糊查询id属性以he开头
//div[ends-with(@id, "he")] #模糊查询id属性以he结尾
——//div/h1——/text() #以/text()为标签中内容//div[@id="head" and @class="s_down"] #逻辑运算与
//title | //price #逻辑运算或
3、安装步骤
1、安装lxml库 pip install lxml
2、安装xpath插件将xpath.crx拖到浏览器可扩展程序中开打xpath调试框式 ctrl + shift + x
3、在python文件中 from lxml import etree
4、创建对象(1)html_tree = etree.parse('XX.html')#解析本地html文件(2)html_tree = etree.HTML(rsponse.read().decode('utf-8')#解析响应文件
5、解析并返回结果list=html_tree.xpath("xpath路径")#返回为一个列表
4、代码实现
import urllib.request
from lxml import etree #重点def create_request(page):url = 'https://www.qiushibaike.com/8hr/page/'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}url = url + str(page) + '/'request = urllib.request.Request(url=url, headers=headers)return requestdef save_content(request):response = urllib.request.urlopen(request)content = response.read().decode('utf-8')return contentdef parse_content(content): #重点。其他部分相似,该部分则是匹配并返回指定数据列表tree = etree.HTML(content)#当前xpath路径 返回的是img标签中的src的值src_list = tree.xpath('//div[@class="thumb"]//img/@src')return src_listdef down_load(src_list):for src in src_list:src = 'https:' + srcname = src.split('/')[-1]file_name = 'qiushibaike/' + nameurllib.request.urlretrieve(url = src,filename=file_name)if __name__ == '__main__':start_page = int(input('请输入起始页码'))end_page= int(input('请输入结束页码'))for page in range(start_page,end_page+1):request = create_request(page)content = save_content(request)src_list = parse_content(content)down_load(src_list)
十一、JsonPath
1. 介绍
类似于XPath在xml文档中的定位,JsonPath表达式通常是用来路径检索或设置Json的。其表达式可以接受“dot–notation”和“bracket–notation”格式,
“dot–notation”:$.store.book[0].title
“bracket–notation”:$[‘store’][‘book’][0][‘title’]
2、操作符
符号 | 描述 |
---|---|
$ | 查询的根节点对象,用于表示一个json数据,可以是数组或对象 |
@ | 过滤器断言(filter predicate)处理的当前节点对象,类似于java中的this字段 |
* | 通配符,可以表示一个名字或数字 |
… | 可以理解为递归搜索,Deep scan. Available anywhere a name is required. |
. | 表示一个子节点 |
[‘’ (, ‘’)] | 表示一个或多个子节点 |
[ (, )] | 表示一个或多个数组下标 |
[start:end] | 数组片段,区间为[start,end),不包含end |
[?()] | 过滤器表达式,表达式结果必须是boolean |
3、资料
- JSONPath 表达式
JSONPath 是参照,xpath表达式来解析xml文档的方式,json数据结构通常是匿名的并且不一定需要有根元素。JSONPaht 用一个抽象的名字$来表示最外层对象。
JOSNPath 表达式可以使用. 符号如下:
$.store.book[0].title
或者使用[] 符号
$['store']['book'][0]['title']
从输入路径来看。内部或者输出的路径都会转化成-符号。
JSONPath 允许使用通配符 * 表示所以的子元素名和数组索引。还允许使用 ‘…’ 从E4X参照过来的和数组切分语法[start:end:step]是从ECMASCRIPT 4 参照过来的。
表达式在下面的脚本语言中可以使用显示的名称或者索引:
$.store.book[(@.length-1)].title
使用’@'符号表示当前的对象,?(<判断表达式>) 使用逻辑表达式来过滤。
$.store.book[?(@.price < 10)].title
这里有个表格,说明JSONPath语法元素和对应XPath元素的对比。
XPath | JSONPath | Description |
---|---|---|
/ | $ | 表示根元素 |
. | @ | 当前元素 |
/ | . or [] | 子元素 |
… | n/a | 父元素 |
// | … | 递归下降,JSONPath是从E4X借鉴的。 |
* | * | 通配符,表示所有的元素 |
@ | n/a | 属性访问字符 |
[] | [] | 子元素操作符 |
| | [,] | 连接操作符在XPath 结果合并其它结点集合。JSONP允许name或者数组索引。 |
n/a | [start🔚step] | 数组分割操作从ES4借鉴。 |
[] | ?() | 应用过滤表示式 |
n/a | () | 脚本表达式,使用在脚本引擎下面。 |
() | n/a | Xpath分组 |
XPath还有很多的语法(本地路径,操作符,和函数)没有列在这里。只要知道xpath和jsonpath脚本之中的不同点就行了。
- []在xpath表达式总是从前面的路径来操作数组,索引是从1开始。
- 使用JOSNPath的[]操作符操作一个对象或者数组,索引是从0开始。
- SONPath 例子
接下我们看jsonpath表示的例子。下面是一个简单的json数据结构代表一个书店(原始的xml文件是)
{ "store": {"book": [ { "category": "reference","author": "Nigel Rees","title": "Sayings of the Century","price": 8.95},{ "category": "fiction","author": "Evelyn Waugh","title": "Sword of Honour","price": 12.99},{ "category": "fiction","author": "Herman Melville","title": "Moby Dick","isbn": "0-553-21311-3","price": 8.99},{ "category": "fiction","author": "J. R. R. Tolkien","title": "The Lord of the Rings","isbn": "0-395-19395-8","price": 22.99}],"bicycle": {"color": "red","price": 19.95}}
}
XPath | JSONPath | 结果 |
---|---|---|
/store/book/author | $.store.book[*].author | 书点所有书的作者 |
//author | $..author | 所有的作者 |
/store/* | $.store.* | store的所有元素。所有的bookst和bicycle |
/store//price | $.store..price | store里面所有东西的price |
//book[3] | $..book[2] | 第三个书 |
//book[last()] | $..book[(@.length-1)] | 最后一本书 |
//book[position()<3] | $..book[0,1]``$..book[:2] | 前面的两本书。 |
//book[isbn] | $..book[?(@.isbn)] | 过滤出所有的包含isbn的书。 |
//book[price<10] | $..book[?(@.price<10)] | 过滤出价格低于10的书。 |
//* | $..* | 所有元素。 |
4、代码实现
import json
import jsonpathobj=json.load(open(r'E:\files\book.json','r'))author_list=jsonpath.jsonpath(obj,'$..author')for author in author_list:print(author)
十二、BeautifulSoup
1、简介
- Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
- Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
- Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。
2、安装(windows)
-
到http://www.crummy.com/software/BeautifulSoup/ 网站 上下载,最新版本是4.3.2。
-
下载完成之后需要解压缩,假设放到C:/python27/下。
-
“运行cmd”—“cd c:\python27\beautifulsoup4-4.3.2”,切换到c:\python27\beautifulsoup4-4.3.2目录下(根据自己解压后所放的目录和自己的版本号修改)。
-
运行命令:setup.py build、setup.py install
-
python命令下 import bs4,没报错说明安装成功。
或者 安装:pip install bs4 导入:from bs4 import BeautifulSoup 创建对象:网上文件生成对象:soup = BeautifulSoup(response.read().decode('utf-8'), 'lxml')本地文件生成对象:soup = BeautifulSoup(open('1.html',encoding='utf-8'), 'lxml')
3、节点定位
标签名查找节点
soup.a 【注】只能找到第一个asoup.a.name 获取标签的名字soup.a.attrs 将属性作为一个字典返回#输出的是整个页面的源代码
# print(soup)#打印的是第一个符合条件的标签
# print(soup.a)#获取标签的名字
# print(soup.a.name)#获取所有的标签的属性 该attrs属性会返回一个字典
# print(soup.a.attrs)#获取标签的属性值
# print(soup.a.attrs.get('name'))
# print(soup.a.attrs['name'])
函数
soup.find(返回一个对象)
soup.find('a'):只找到第一个a标签
soup.find('a', title='名字')
soup.find('a', class_='名字')#找到的是第一个符合条件的标签类似与 soup.a
# a = soup.find('a')# #方法的返回值类型 是tag类型
# print(type(a))
# print(a)#只能通过title属性值来寻找标签 方法的返回值类型也是一个tag类型
# a = soup.find('a',title='qf1')
# print(type(a))
# print(a)#不能以name属性来查找标签
# a = soup.find('a',name='qf')
# print(type(a))
# print(a)#笔试题的时候容易犯错 注意因为class是一个关键字 所以不可直接使用
#想使用需要加_
# a = soup.find('li',class_='js')
# print(a)
#查找所有的a 返回的是一个列表
soup.find_all(返回一个列表)
find_all(返回一个列表)
find_all('a') 查找到所有的a
find_all(['a', 'span']) 返回所有的a和span
find_all('a', limit=2) 只找前两个a# a_list = soup.find_all('a')
# print(a_list)#组合查询 返回的也是一个列表(包含a、li标签)
# list = soup.find_all(['a','li'])
# print(list)#查找前几个对象 返回的类型也是一个列表
# li_list = soup.find_all('li',limit=3)
# print(li_list)
select(根据选择器得到节点对象)【推荐】
与xpath对比:
#xpath: //div[@id=“listContent”]//div/div/div/div/div[2]/a/@title
#soup: #listContent > div > div > div > div > div[1] > a[title]
#查询所有的a 返回的是一个list列表
# a = soup.select('a')
# print(type(a))
# print(a)#id以井号开头 返回的类型也是一个列表
# a = soup.select('#gl')
# print(type(a))
# print(a)#类选择器以.开头
# a = soup.select('.zx')
# print(type(a))
# print(a)#注意 参数中不可以写@
# #扩展 select返回的是list列表 findall返回的是一个set列表(重点类型不一样,类型不同,不去重)
# li = soup.select('li[id]')
# print(li)#注意 可以加双引号 也可以不加双引号 也没有@
# li = soup.select('li[id="gl"]')
# print(li)#相当于xpaht中// 是子孙类标签
# li = soup.select('#ig li')
# print(li)#注意注意注意 一定要加空格 > 代表的是第一级子标签
# li = soup.select('#ig > li')
# print(li)#获取soup对象的中的所有的a 和 li的标签,通过列表显示返回
# li = soup.select('li,a')
# print(li)
获取子孙节点
contents:返回的是一个列表#【注意】中间也会得到很多的换行符#获取子孙节点 返回的是一个列表#print(soup.body.contents)descendants:返回的是一个生成器# for tag in soup.body.descendants:# print(tag)
4、节点信息
获取节点内容
# a = soup.select('#divtest')[0]
#列表中是没有string和get_text()方法
#如果该(div)标签下 有子标签 <p>我还在呢</p> 那么就获取不到数据 返回none # print(a.string) #不管该标签(div)下有没有子标签(p) 都可以返回子孙标签中的内容 在企业级开发中我们 #一般都使用get_text()
# print(a.get_text())
获取节点的属性
#返回该标签自身的名字
#a = soup.select('#divtest')[0] #<div id = 'divtest'>……<div>
#print(a.name) #div#将属性值作为一个字典返回,{属性名称:属性值}
#a = soup.select('#divtest')[0] #<div id = 'divtest'>……<div>
#print(a.attrs) #{'id': 'divtest'}#获取该标签自身的内部属性
#a = soup.select('#divtest')[0] #<div title = 'divtest'>……<div>
#a.attrs.get('title')【常用】
#a.get('title')
#a['title']
5、代码实现
import urllib.request
from bs4 import BeautifulSoup
from Item1 import YCW
import jsonurl = 'http://www.chinahr.com/sou/?city=36%2C400&keyword=python%E5%BC%80%E5%8F%91'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')soup = BeautifulSoup(content,'lxml')
ul_list = soup.select('.jobList > ul')
YCWs = []
for ul in ul_list:job = ul.find('li',class_="l1").find_all('span')[0].get_text()cname = ul.find('li',class_="l1").find('span',class_="e3").get_text().strip('\n')salary = ul.find('li',class_="l2").find('span',class_="e2").get_text()ycw = YCW(job,cname,salary)YCWs.append(ycw.__dict__)str = json.dumps(YCWs,ensure_ascii=False)with open('ycw.json','w',encoding='utf-8')as fp:fp.write(str)
十三、Selenium(自动化测试)
浏览器自动化测试框架
1、简介
Selenium [1] 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),[Mozilla Firefox](https://baike.baidu.com/item/Mozilla%20Firefox/3504923),Safari,Google Chrome,Opera等。这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成 .Net、Java、Perl等不同语言的测试脚本。
Selenium是一个用于Web应用程序测试的工具。Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样,支持通过各种driver(FirfoxDriver,IternetExplorerDriver,OperaDriver,ChromeDriver)驱动真实浏览器完成测试,selenium也是支持无界面浏览器操作的。比如说HtmlUnit和PhantomJs。
谷歌浏览器和chromeDriver的对应关系:http://blog.csdn.net/huilan_same/article/details/51896672
谷歌驱动的下载路径:http://chromedriver.storage.googleapis.com/index.html
安装:pip install selenium
导入:from selenium import webdriver
创建对象:browser = webdriver.Chrome(‘chromedriver.exe’)#创建一个浏览器对象,.exe文件为浏览器驱动
2、操作谷歌浏览器
需求打开浏览器 然后再搜索框中输入 韩红 然后点击百度一下 然后回退 前进 并关闭浏览器
from selenium import webdriver
import time
#创建一个浏览器对象 .exe文件为浏览器驱动 为操纵浏览器提供可能
browser = webdriver.Chrome(r'E:\Project_python\python_directory\Knowledge\爬虫\files\exe\chromedriver.exe')#路由
url = 'http://www.baidu.com/'#通过浏览器发送请求,驱动谷歌浏览器,打开url指定的页面
browser.get(url=url)#元素定位,指定id=kw的标签,
text = browser.find_element_by_id('kw')#在text的标签中输入:"韩红"
text.send_keys('韩红')time.sleep(3)#睡眠3秒#元素的定位,定位到id=su的标签
button = browser.find_element_by_id('su')#点击元素定位到的按钮
button.click()time.sleep(2)#睡眠2秒#回到当前页面的上一个页面
browser.back()time.sleep(2)#睡眠2秒#进入当前页面的下一页面,也就是缓存的上次后退的页面
browser.forward()time.sleep(1)#睡眠1秒#关闭浏览器
browser.quit()
3、元素定位
自动化要做的就是模拟鼠标和键盘来操作来操作这些元素,点击、输入等等。操作这些元素前首先要找到它们,WebDriver提供很多定位元素的方法
#find_element_by_id
id = browser.find_element_by_id('kw')#获取id=kw的标签,返回的为单个标签#find_elements_by_name name是标签中属性值 方法的返回值类型是一个列表
name = browser.find_elements_by_name('wd')#find_elements_by_link_text 查找的是页面中的连接的文本
text = browser.find_elements_by_link_text('地图')#find_elements_by_tag_name 标签的名字 方法的返回值类型是一个列表
tagname = browser.find_elements_by_tag_name('input')#以下两个是以分别使用xpath、BeautifulSoup.selector函数 的语法 查询指定的标签
#find_elements_by_xpath
xpath = browser.find_elements_by_xpath('//input[@id="kw"]')
#find_elements_by_css_selectorbs4_s = browser.find_elements_by_css_selector('#kw')
4、访问元素信息
#通过查询到合适的标签bs4_s bs4_s[0]的信息
bs4_s = browser.find_elements_by_css_selector('#kw')
bs4_s[0].get_attribute('name') #获取元素属性
bs4_s[0].id #获取id
bs4_s[0].tag_name #获取标签名
bs4_s[0].text #获取元素文本
5、交互浏览器
打开浏览器 browser.get(url=url) --打开浏览器,访问指定路由
点击 .click()
输入内容 .send_keys()
后退操作 browser.back()
前进操作 browser.forword()
请求页源码 browser.page_source
关闭浏览器 browser.quit()
模拟JS滚动 (以下1、2并无区别)(1)js = 'document.body.scrollTop=100000'(2)js='document.documentElement.scrollTop=100000'执行js代码:execute_script(js)
6、PhantomJS浏览器
**1、简介:**是一个无界面的浏览器,支持页面元素查找,js的执行等,由于不进行css和gui渲染,运行效率要比真实的浏览器要快很多
2、如何使用
1.获取PhantomJS.exe文件路径path,创建浏览器操作对象对象browser = webdriver.PhantomJS(r'E:\files\exe\phantomjs.exe')
2、驱使浏览器访问指定的路由browser.get(url)
3.保存屏幕快照,也就是将访问当前的页面保存为图片。browser.save_screenshot('baidu.png')
4.基本操作的和有界面是浏览器是相同的。
3、代码实现
from selenium import webdriver
import time
browser = webdriver.PhantomJS('phantomjs.exe')url = 'http://www.baidu.com/'browser.get(url=url)
#获取网页源码 注意注意 没有() 不是一个方法
#通过selenium获取的是一个完整网页源码 不涉及有部分数据返回的情况
#因为我们操作的是一个真实的浏览器
#由于phantomjs是一个无界面的浏览器 所以不会给我们显示页面响应
#快照功能 专门用来给无界面浏览器进行拍照
# browser.save_screenshot('baidu.png')
# print(browser.page_source)
text = browser.find_element_by_id('kw')
text.send_keys('刘诗诗')
browser.save_screenshot('a.png')
button = browser.find_element_by_id('su')
button.click()
time.sleep(2)
browser.save_screenshot('b.png')
7、Chrome handless
1、系统要求
Chrome
Unix\Linux 系统需要 chrome >= 59
Windows 系统需要 chrome >= 60Python3.6
Selenium==3.4.*
ChromeDriver==2.31
2、配置文件
from selenium import webdriver
#这个是浏览器自带的 不需要我们再做额外的操作
from selenium.webdriver.chrome.options import Optionsdef share_browser():#初始化chrome_options = Options()chrome_options.add_argument('--headless')chrome_options.add_argument('--disable-gpu')#浏览器的安装路径 打开文件位置#这个路径是你谷歌浏览器的路径path = r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'chrome_options.binary_location = pathbrowser = webdriver.Chrome(chrome_options=chrome_options)return browser
3、正常代码实现
from handless import share_browser#这导入的是上面配置代码,将其封装为和有界面的浏览器操作类似browser = share_browser()
url='http://www.baidu.com/'browser.get(url)
browser.save_screenshot('handless1.png')
十四、requests(自带)
1、简介
Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的,所以它比 urllib 更加 Pythoner。更重要的一点是它支持 Python3 哦
官方文档:http://cn.python-requests.org/zh_CN/latest/
快速上手:http://cn.python-requests.org/zh_CN/latest/user/quickstart.html
2、安装步骤
1、安装: pip install requests
2、导入: import requests
3、将requests作为关键使用,用其get、post方法实现请求
3、常用方法
1、response函数、属性
import requests
url = 'http://www.baidu.com/'
response = requests.get(url=url)
print(type(response))
print(response)
# 设置响应的编码格式 不是一个方法 而是一个属性
response.encoding = 'utf-8'
# 获取网站的源码
print(response.text)
# 获取请求路径
print(response.url)
# 获取响应的字节类型
print(response.content)
# 获取响应的请求头
print(response.headers)
# 获取状态码
print(response.status_code)
2、get请求
import requestsurl = 'http://www.baidu.com/s'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}data = {'kw':'周杰伦'}#requests没有进行编码 没有请求对象的定制 注意get请求的参数是params ?可加可不加r = requests.get(url=url,params=data,headers=headers)
r.encoding = 'utf-8'print(r.text)
3、post请求
import json
import requestsurl = 'https://fanyi.baidu.com/sug'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}data = {'kw': 'china',}#post请求方式data=data方式 传递form表单数据 与get方式不同
r = requests.post(url=url , data=data , headers=headers )obj = json.loads(r.text)
str = json.dumps(obj,ensure_ascii=False)with open('post.json','w',encoding='utf-8')as fp:fp.write(str)
总结:
1:get请求的参数名字是params post请求的参数的名字是data
2 请求资源路径后面可以不加?
3 不需要手动编解码
4 不需要做请求对象的定制
4、proxy定制
import requestsurl = 'https://www.baidu.com/s?wd=ip'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}proxy={'https':'114.113.126.87:80'}r = requests.get(url=url,headers=headers,proxies=proxy)with open('ip.html','w',encoding='utf-8')as fp:fp.write(r.text)
5、cookie定制
http://bbs.chinaunix.net/
账号密码
action123321
action123
个人资料:http://bbs.chinaunix.net/home.php?mod=space&uid=31527684&do=profile
import requests
import urllib.request
from bs4 import BeautifulSoupget_url = 'http://bbs.chinaunix.net/member.php?mod=logging&action=login&logsubmit=yes'
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',}s = requests.Session()r = s.get(url=get_url,headers=headers)
soup = BeautifulSoup(r.text,'lxml')
formhash = soup.select('input[name="formhash"]')[0].attrs.get('value')
print(formhash)post_url = 'http://bbs.chinaunix.net/member.php?mod=logging&action=login&loginsubmit=yes&loginhash=LCfS6'data = {'formhash':formhash,'referer':'http://bbs.chinaunix.net/','username':'action123321','password':'action','loginsubmit':'true','return_type':''
}
r1 = s.post(url=post_url, headers=headers,data=data)
r1.encoding = 'gbk'
print(r1.text)
"""
账号密码
595165358@qq.com
action
"""
import requests
from bs4 import BeautifulSoups = requests.Session()get_url = 'http://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36',
}r = s.get(url=get_url, headers=headers)soup = BeautifulSoup(r.text, 'lxml')
a = soup.select('#__VIEWSTATE')[0].attrs.get('value')
b = soup.select('#__VIEWSTATEGENERATOR')[0].attrs.get('value')# 获取验证码图片的url
image_url = 'http://so.gushiwen.org' + soup.select('#imgCode')[0].attrs.get('src')
# 将图片下载到本地
# print(image_url)
# import urllib.request
r = s.get(image_url)
# urllib.request.urlretrieve(image_url, './yanzhengma.jpg')
with open('./yanzhengma.jpg', 'wb') as fp:fp.write(r.content)# 让用户输入验证码
code = input('请输入验证码:')post_url = 'http://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx'
data = {'__VIEWSTATE': a,'__VIEWSTATEGENERATOR': b, 'from': 'http://so.gushiwen.org/user/collect.aspx','email': '595165358@qq.com','pwd': 'action','code': code,'denglu': '登录',
}r = s.post(post_url, headers=headers, data=data)print(r.text)
6、云打码平台
用户登陆
actionuser
action
开发者登陆
actioncode
action
需要观 看开发者里的开发步骤
操作视屏在爬虫第6天中
贰、爬虫框架
十五、scrapy简单框架
1、简介
Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。
Scrap,是碎片的意思,这个Python的爬虫框架叫Scrapy。
2、安装框架
安装:pip install scrapy
如果安装有错误!!!!pip install Scrapybuilding 'twisted.test.raiser' extensionerror: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools解决方案http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 下载twisted对应版本的whl文件(如我的Twisted-17.5.0-cp36-cp36m-win_amd64.whl),cp后面是python版本,amd64代表64位,运行命令:pip install C:\Users\...\Twisted-17.5.0-cp36-cp36m-win_amd64.whlpip install Scrapy报错 win32
解决方法pip install pywin32
3、原理解析
引擎:自动运行,无需关注,会自动组织所有的请求对象,分发给下载器
下载器:从引擎处获取到请求对象后,请求数据
spiders:Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。
调度器:有自己的调度规则,无需关注管道(Item pipeline):
最终处理数据的管道,会预留接口供我们处理数据
当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。
每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。
以下是item pipeline的一些典型应用:1. 清理HTML数据2. 验证爬取的数据(检查item包含某些字段)3. 查重(并丢弃)4. 将爬取结果保存到数据库中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3c80mOTJ-1592465361872)(C:\Users\Administrator\Desktop\python第四阶段\图片\scrapy框架原理.png)]
4、创建并使用
1、创建项目:scrapy startproject 项目名称目录结构:(例如创建:scrapy startproject scrapyProject)scrapyProject└─ scrapyProject└─spiders│ └─__inid__.py│ └─ReadBook.py(是实现爬虫核心功能的文件,暂无)│└─__init__.py └─items.py(定义数据结构的地方)└─middlewares.py(中间件)└─pipelines.py(管道文件)└─settings.py(配置文件)scrapy.cfg
2、创建核心文件(1)cd scrapyProject/scrapyProject/spiders(2)scrapy genspider 文件名 网址(文件名不可项目名重复,网址尽量是起始页网址)#在spiders文件夹下产生 ReadBook.py 文件
3、项目创建完成
4、运行爬虫文件 scrapy crawl 文件名 (例如:scrapy crawl ReadBook)
5、测试工具:Scrapy shell
安装:pip install Jupyter
使用:终端输入:scrapy shell "http://www.baidu.com"#返回的是response对象response.body:二进制类型response.text:编码类型response.url:查看urlresponse.status:查看状态码response.xpath():使用xpath路径查询特定元素,返回一个selector对象(使用extract_first())response.css():使用css_selector查询元素,返回一个selector对象选择文本在路径内使用 ::text//response.css('#su::text').extract_first()选择属性在路径内使用 ::attr("属性名称")注意:1. attr后面没有字母s2. attr后面使用()小括号response.css('#su::attr(value)')selector对象:对response对象进行解析后得到的对象类型,需要进一步解析成字符串,才能在代码中使用使用xpath请求到的对象是一个selector对象,需要进一步使用extract()方法拆包,转换为unicode字符串返回第一个解析到的值,如果列表为空,此种方法也不会报错,会返回一个空值、此方法作用在列表之上selector对象也支持xpath查询selector对象也支持css语句查询item对象:item对象:对象是种简单的容器,保存了爬取到得数据。 其提供了 类似于字典(dictionary-like) 的API以及用于声明可用字段的简单语法。dict(itemobj):可以使用dict方法直接将item对象转换成字典对象Item(dicobj):也可以使用字典对象创建一个Item对象
6、日志信息和日志等级
日志级别
级别:CRITICAL:严重错误ERROR:一般错误WARNING:警告INFO: 一般信息DEBUG:调试信息默认的日志等级是DEBUG
只要出现了DEBUG或者DEBUG以上等级的日志
那么这些日志将会打印
设置
默认的级别为DEBUG,会显示上面所有的信息
在配置文件中 settings.py
LOG_FILE : 将屏幕显示的信息全部记录到文件中,屏幕不再显示
LOG_LEVEL : 设置日志显示的等级,就是显示哪些,不显示哪些例如:
#默认的日志等级有5个 控制台上会显示 该等级以及该等级之上的所有的日志信息
#如果想把日志保存到日志文件中 那么需要定义一个LOG_FILE 值 必须是一个以log为
#结尾的文件
LOG_LEVEL = 'ERROR'
LOG_FILE = 'log1.log'
7、get请求
起始的get请求
也就是含有start_urls = [‘http://www.qiushibaike.com/’],将get请求参数放在链接中
# -*- coding: utf-8 -*-
import scrapy
class QbSpider(scrapy.Spider):name = 'qb'allowed_domains = ['www.qiushibaike.com']start_urls = ['http://www.qiushibaike.com/']#注意:此方法一定要返回一个可迭代的对象def parse(self, response):#注意:response.xpath返回的数据类型是seletor的列表name_list = response.xpath('//div[@id="content-left"]/div/div[starts-with(@class,"author clearfix")]/a[2]/h2/text()')src_list = response.xpath('//div[@id="content-left"]/div/div[starts-with(@class,"author clearfix")]/a[1]/img/@src')users = []if len(name_list) == len(src_list):for i in range(len(name_list)):name = name_list[i].extract().strip('\n')src = src_list[i].extract()user = {}user['name'] = nameuser['src'] = srcusers.append(user)return users
在请求中使用get请求
scrapy.Request(url=url, callback=self.parse_item, meta={'item': item}, headers=headers)url: 要请求的地址callback:响应成功之后的回调函数(self.parse_item)meta: 参数传递,一般传递item对象headers: 定制头信息,一般不用
8、post请求
起始的post请求
也就是不在是框架一开始就发送接收response的对象,而是重写start_requests函数(也就是重谢发送get方法)。所以之前的start_urls = [‘http://www.fang.com/SoufunFamily.htm’]也就没用了
# -*- coding: utf-8 -*-
import scrapy
class BaiduSpider(scrapy.Spider):name = 'baidu'allowed_domains = ['www.baidu.com']# 如果想要自己直接发送post请求,则需要重写这个方法。# 这个方法以前就是遍历start_urls列表,生成请求对象的def start_requests(self):post_url = 'http://fanyi.baidu.com/sug'word = 'world'data = {'kw': word}yield scrapy.FormRequest(url=post_url, formdata=data, callback=self.parse_post)def parse_post(self, response):print(response.text)
在请求中使用post请求
【注】如果直接发送post请求,start_urls这个列表就没有用了,因为你重写了start_requests(self)这个方法,原来的parse方法也没用了百度翻译
scrapy.FormRequest(url=url, headers=headers, callback=self.parse_item, formdata=data)url: 要发送的post地址headers:可以定制头信息callback: 回调函数 formdata: post所携带的数据,这是一个字典
9、代理ip
通过下载中间件来进行添加(1)到settings.py中,打开一个选项DOWNLOADER_MIDDLEWARES = {'postproject.middlewares.Proxy': 543,}(2)到middlewares.py中写代码from scrapy import signalsimport randomclass LagoprojectSpiderMiddleware(object):def process_request(self, request, spider):#路径就是字符串 https\http要和爬虫文件url请求相对应daili=['https://120.27.126.223:808','https://120.92.74.237:3128','https://101.37.14.151:3128',]ip=random.randint(0,2)request.meta['proxy'] = daili[ip]return None
10、cookie登陆
也就是判读登录页面逻辑(请求路径、请求方式、请求体信息 )、一直请求页面
# -*- coding: utf-8 -*-
import scrapy
import urllib.requestclass DoubanSpider(scrapy.Spider):name = 'douban'allowed_domains = ['douban.com']start_urls = ['https://accounts.douban.com/login']def parse(self, response):# 去查找有没有验证码# 【注】如果找不到,那么返回Noneimage_url = response.xpath('//img[@id="captcha_image"]/@src').extract_first()# exit()# 如果没有验证码图片,image_url就是Noneif not image_url:data = {'source': '','redir': 'https://www.douban.com','form_email': 'fdsfdsf@qq.com','form_password': '1231231','login': '登录',}else:# 获取验证码idcaptcha_id = response.xpath('//input[@name="captcha-id"]/@value').extract_first()# 保存验证码图片,并且提示用户输入验证码urllib.request.urlretrieve(image_url, './douban.png')yanzhengma = input('请输入验证码:')data = {'source': '','redir': 'https://www.douban.com','form_email': 'fdfdsfsf@qq.com','form_password': '312321313123','captcha-solution': yanzhengma,'captcha-id': captcha_id,'login': '登录',}post_url = 'https://accounts.douban.com/login'yield scrapy.FormRequest(url=post_url, formdata=data, callback=self.hehe)def hehe(self, response):url = 'https://www.douban.com/accounts/'yield scrapy.Request(url=url, callback=self.dongguan)def dongguan(sef, response):with open('dong.html', 'wb') as fp:fp.write(response.body)
11、存储到mysql
settings.py
连接数据库的参数
一共有6个
其中只有端口号不需要加字符串 因为端口号是整数
DB_HOST = '192.168.231.128'
DB_PORT = 3306
DB_USER = 'root'
DB_PWD = '1234'
DB_NAME = 'test'
DB_CHARSET = 'utf8'
pipelines.py
# 导入settings的所有配置
from scrapy.utils.project import get_project_settings
import pymysqlclass MysqlPipeline(object):"""docstring for MysqlPipeline"""def __init__(self):settings = get_project_settings()self.host = settings['DB_HOST']self.port = settings['DB_PORT']self.user = settings['DB_USER']self.pwd = settings['DB_PWD']self.name = settings['DB_NAME']self.charset = settings['DB_CHARSET']#调用函数self.connect()def connect(self):self.conn = pymysql.connect(host=self.host,port=self.port,user=self.user,password=self.pwd,db=self.name,charset=self.charset)self.cursor = self.conn.cursor()def close_spider(self, spider):self.conn.close()self.cursor.close()def process_item(self, item, spider):sql = 'insert into book(image_url, book_name, author, info) values("%s", "%s", "%s", "%s")' % (item['image_url'], item['book_name'], item['author'], item['info'])# 执行sql语句self.cursor.execute(sql)commitreturn item
十六、CrawlSpider
1、简介
CrawlSpider:继承自scrapy.Spider,简单来说就是爬去规则的有下一页(相同模板)的网页数据。
CrawlSpider可以定义规则,再解析html内容的时候,可以根据链接规则提取出指定的链接,然后再向这些链接发送请求,所以如果有需要跟进链接的需求,意思就是爬取了网页之后,需要提取链接再次爬取,使用CrawlSpider是非常合适的。
2、提取连接
链接提取器,在这里就可以写规则提取指定链接
scrapy.linkextractors.LinkExtractor(allow = (), # 正则表达式 提取符合正则的链接deny = (), # (不用)正则表达式 不提取符合正则的链接allow_domains = (), # (不用)允许的域名deny_domains = (), # (不用)不允许的域名restrict_xpaths = (), # xpath,提取符合xpath规则的链接restrict_css = () # 提取符合选择器规则的链接)
模拟使用:
正则用法:links1 = LinkExtractor(allow=r'list_23_\d+\.html')
xpath用法:links2 = LinkExtractor(restrict_xpaths=r'//div[@class="x"]')
css用法:links3 = LinkExtractor(restrict_css='.x')
提取连接:
link.extract_links(response)
注意事项:
【注1】callback只能写函数名字符串, callback='parse_item'
【注2】在基本的spider中,如果重新发送请求,那里的callback写的是 callback=self.parse_item
【注--稍后看】follow=true 是否跟进 就是按照提取连接规则 提取 follow是有默认值的 如果我们不加follow 那么如果有callback follow是false 如果没有callback follow是true
3、CrawlSpider爬虫案例
创建项目:scrapy startproject dushuproject
跳转到spiders路径 cd\dushuproject\dushuproject\spiders
创建爬虫类:scrapy genspider -t crawl read www.dushu.com
read.py(spiders)#爬虫文件
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import BookItemclass DushuSpider(CrawlSpider):name = 'dushu'allowed_domains = ['www.dushu.com']start_urls = ['https://www.dushu.com/book/1078.html']# 规则# 参数一:链接提取器;# 参数二:将提取的链接发起网络请求,解析的方法;# 参数三:follow = True# 从提取的链接的网页中,是否还要再次提取# rules = (# Rule(LinkExtractor(allow=(r'/book/1078_\d+\.html',r'/book/1163\.html' ,r'/book/1163_\d+\.html')), callback='parse_item', follow=True),)rules = (Rule(LinkExtractor(allow=(r'/book/1078_\d+\.html')), callback='parse_item', follow=False), )def parse_item(self, response):bookslist = response.xpath('//div[@class="bookslist"]/ul/li')for book in bookslist:item = BookItem()item['book_image'] = book.xpath('.//img/@src').extract_first()item['book_name'] = book.xpath('.//img/@alt').extract_first()item['book_author'] = book.xpath('.//p[1]/a/text()').extract_first()item['book_info'] = book.xpath('.//p[2]/text()').extract_first()yield item
items.py#items对象
import scrapy
class DushuprojectItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()image_url = scrapy.Field()book_name = scrapy.Field()author = scrapy.Field()info = scrapy.Field()
settings.py#配置信息
#请求头
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'#君子协议
# Obey robots.txt rules
ROBOTSTXT_OBEY = False#设置管道
ITEM_PIPELINES = { 'dushuproject.pipelines.DushuprojectPipeline': 300,'dushuproject.pipelines.MysqlPipeline': 299,
}
#设置数据库
DB_HOST = '127.0.0.1'
DB_PORT = 3306
DB_USER = 'root'
DB_PWD = '1234'
DB_NAME = 'test'
DB_HARSET = 'utf8'#代理
# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {'daili.middlewares.DailiDownloaderMiddleware': 543,
}
items.py#items对象
import scrapy
class DushuprojectItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()image_url = scrapy.Field()book_name = scrapy.Field()author = scrapy.Field()info = scrapy.Field()
pipelines.py#管道
#下载以及存到数据库
#导入信息
class DushuprojectPipeline(object):def open_spider(self, spider):self.fp = open('book.json', 'w', encoding='utf-8')def process_item(self, item, spider):obj = dict(item)string = json.dumps(obj, ensure_ascii=False)self.fp.write(string + '\n')return itemdef close_spider(self, spider):self.fp.close()#存储到数据库
from scrapy.utils.project import get_project_settings
import pymysql
class MysqlPipeline(object):"""docstring for MysqlPipeline"""def __init__(self):settings = get_project_settings()self.host = settings['DB_HOST']self.port = settings['DB_PORT']self.user = settings['DB_USER']self.pwd = settings['DB_PWD']self.name = settings['DB_NAME']self.charset = settings['DB_CHARSET']self.connect()def connect(self):self.conn = pymysql.connect(host=self.host,port=self.port,user=self.user,passwd=self.pwd,db=self.name,charset=self.charset)self.cursor = self.conn.cursor()def process_item(self, item, spider):sql = 'insert into book(image_url, book_name, author, info) values("%s", "%s", "%s", "%s")' % (item['image_url'], item['book_name'], item['author'], item['info'])# 执行sql语句self.cursor.execute(sql)self.conn.commit()return itemdef close_spider(self, spider):self.conn.close()self.cursor.close()
middlewares.py#代理
from scrapy import signalsclass DailiDownloaderMiddleware(object):def process_request(self, request, spider):#路径就是字符串 https\http要和爬虫文件url请求相对应request.meta['proxy'] = 'https://61.128.208.94:3128'return None
十七、分布式爬虫
1、分布式安装
windows:pip install scrapy_redis
linux:pip3 install scrapy_redis
2、scrapy、scrapy-redis区别
scrapy是一个通用的爬虫框架,但是这个框架不支持分布式
scrapy_redis就是为了实现scrapy的分布式而诞生的,它提供了一些基于redis的组件
https://www.cnblogs.com/nick477931661/p/9135497.html(原理解析)
官方例子简单介绍:https://github.com/rmax/scrapy-redis
dmoz.py 这就是传统的CrawlSpider,这个的目的就是让数据保存到redis中, 运行方式 scrapy crawl dmoz
myspider_redis.py 继承了RedisSpider,start_urls被redis_key给替换了,allow_domains这个列表不变
【注】官方说的能用__init__方法来替换allow_domains不支持目前的版本
mycrawler_redis.py 继承了RedisCrawlSpider,其它的和上面的myspider_redis.py是一样的
【注】后两种爬虫的运行方式是
scrapy runspider myspider_redis.py
scrapy runspider mycrawler_redis.py
注】from scrapy_redis.spiders import RedisSpider
from scrapy_redis.spiders import RedisCrawlSpider
这两个就是scrapy_redis新增加的两个组件,都是继承自官方的Spider、CrawlSpider
注意:DOWNLOAD_DELAY = 1 下载时延
【注】在爬取网站的时候,将这个选项打开,给对方一条活路
3、多台电脑部署分布式
现在有4台电脑
windows centos ubuntu macos
windows上面安装的是redis服务器,master端
slave端: centos、ubuntu、macos都从redis上面获取请求,或者将请求添加到redis服务器中
slave端首先启动,页面就会停止在那里等待指令这个时候master通过lpush向队列中添加一个起始url,其中一个slave端获取到这个url开始爬取,这个slave端会将解析之后的很多url再次的添加到redis服务中,然后redis服务再从请求队列中向每个slave端分发请求,最终直到所有请求爬取完毕为止分布式步骤 '''
1 将爬虫主类继承的类为RedisCrawlSpider
2 导入RedisCrawlSpider的库
3 删除多余的库
4 由于默认提供的init方法不能使用 所以我们需要自己添加allowed_domains
5 注释start_urls 因为start_urls是由master给的 所以不能自己去写起始的url
eg:大哥带我们去追女生 大哥一声令下 我们才知道去追谁
6 添加redis_key 其实际就是lpush的key 也就是由master端给的起始的url
7 定义提取连接的规则
8 运行 scrapy runspider 文件的名字(fenbushi.py)
9 由master端的redis 给起始的url命令lpush redis_key的值 起始的urllpush fen:start_urls http://www.ygdy8.net/html/gndy/dyzz/index.html
10 修改settings① 添加三个组件② redis管道以及master的redis配置🌂 延迟下载 注意素质
'''
settings.py文件配置
#指纹去重组件 eg: 10000条数据 可能会重复的数据爬取 但是由于指纹
#去重组建会自动去重 我们就不需要关心重复数据
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#调用器组件
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#在爬取的过程中允许暂停
SCHEDULER_PERSIST = True
# 配置存储的redis服务器
REDIS_HOST = '10.11.52.62'
REDIS_PORT = 6379
#延迟下载 注意素质
DOWNLOAD_DELAY = 1#在管道中加入—'scrapy_redis.pipelines.RedisPipeline': 400,—开启缓存redis管道
ITEM_PIPELINES = {'movie.pipelines.MoviePipeline': 300,#只要开启管道 那就会把数据保存到redis中 注意这个管道没有方法'scrapy_redis.pipelines.RedisPipeline': 400,
}
爬虫文件.py
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import Rule
from movie.items import MovieItem
from scrapy_redis.spiders import RedisCrawlSpider
'''
1 修改继承的类为RedisCrawlSpider
2 导入RedisCrawlSpider的库
3 删除多余的库
4 由于默认提供的init方法不能使用 所以我们需要自己添加allowed_domains
5 注释start_urls 因为start_urls是由master给的 所以不能自己去写起始的url
eg:大哥带我们去追女生 大哥一声令下 我们才知道去追谁
6 添加redis_key 其实际就是lpush的key 也就是由master端给的起始的url
7 定义提取连接的规则
8 运行 scrapy runspider 文件的名字(fenbushi.py)
9 由master端的redis 给起始的url命令lpush redis_key的值 起始的urllpush fen:start_urls http://www.ygdy8.net/html/gndy/dyzz/index.html
10 修改settings① 添加三个组件② redis管道以及master的redis配置🌂 延迟下载 注意素质
'''
class FenbushiSpider(RedisCrawlSpider):name = 'fenbushi'allowed_domains = ['www.ygdy8.net']redis_key = 'fen:start_urls'rules = (Rule(LinkExtractor(allow=r'list_23_\d+.html'), callback='parse_item', follow=True),)def parse_item(self, response):a_list = response.xpath('//div[@class="co_content8"]//table//a')for a in a_list:# 要注意关注seletor对象中的data属性值title = a.xpath('./text()').extract_first()href = a.xpath('./@href').extract_first()url = 'http://www.ygdy8.net' + hrefmovie = MovieItem(title=title)# yield Request(参数) url 发送的请求 # callback 执行的方法 meta就是 响应时候携带的参数yield scrapy.Request(url=url, callback=self.parse_detail, meta={'movie': movie})def parse_detail(self, response):movie = response.meta['movie']src = response.xpath('//div[@id="Zoom"]//p[1]/img[1]/@src').extract_first()movie['src'] = srcyield movie
slave端执行
在多个slave配置相同代码、都连接到master端的redis上
scrapy runspider 爬虫文件.py
master端进入redis
向队列中添加起始url
这个key就是你代码中写的 redis_key
lpush fen:start_urls ‘http://www.dytt8.net/html/gndy/dyzz/index.html’
叁、零散知识点
三十、json对象的转换
1、json.loads()
是将字符串转化为python对象
eg:
with open('book.json','r',encoding='utf-8') as fp:json_string = fp.read()
ret = json.loads(json_string)
print(ret)
2、json.dumps()
将python对象转化为json格式的字符串
3、json.load()
读取json格式的文本,转化为python对象
json.load(open(a.json))
4、json.dump()
将python对象写入到文本中
三一、redis的安装
linux下Python环境搭建、scrapy安装:见–linux下scrapy安装.txt
1、windows
下载msi安装包,安装过程需要将添加环境变量、过滤防火墙选中,内存使用默认100M即可启动:cd C:\Program Files\Redis:跳转到redis的安装目录下redis-server.exe redis.windows.conf:启动redis服务redis-cli:本地连接发生启动错误creating server tcp listening socket 127.0.0.1:6379: bind No error1. redis-cli.exe2. shutdown3. exit4. redis-server.exe redis.windows.conf远程连接:
windows上面的redis配置文件中有限制,只允许本机连接,所以我们需要来修改一下配置,让远程linux连接来到redis的安装路径 C:\Program Files\Redisredis的配置文件就是 redis.windows.conf修改配置文件第56行 注释掉这一行 前面添加#号第75行 protected-mode no远程连接:指令:(默认端口号都是6379,可以不加)redis-cli -h host -p port redis-cli -h 10.11.53.141
2、linux
linux1、安装redistar -zxvf redis-3.2.8.tar.gzcp -r ./redis-3.2.8 /usr/local/rediscd /usr/local/redismake install如果有错,输入这个指令make MALLOC=libccd src./redis-server //redis端口号默认为63792、设置开机启动cd /usr/local/rediscp redis.conf redis_6379.confvim redis_6379.conf第128行 daemonize yescd utils/cp redis_init_script redis_init_script_6379vim redis_init_script_6379EXEC=/usr/local/redis/src/redis-serverCLIEXEC=/usr/local/redis/src/redis-cliCONF="/usr/local/redis/redis_6379.conf"启动 ./redis_init_script_6379 start查看是否启动 ps -ef | grep redis添加到开机启动中vim /etc/rc.local添加一行/usr/local/redis/utils/redis_init_script_6379 start
3、客户端安装
客户端安装
图形化界面操作redis数据库
select 0-15 用来切换数据库redis常见问题:https://blog.csdn.net/hjm4702192/article/details/80518856