Python-爬虫
- ■ 控制台抓包
- ■ 爬虫分类
- ■ urllib.request(请求模块)
- ■ User-Agent
- ■ urllib.parse(URL地址编码模块)
- ■ 示例一:抓取输入名字百度贴吧的几页的html
- ■ 示例二 :猫眼电影-榜单-top100榜
- ■ 示例三 :猫眼获取数据保存到mongodb
- ■ 示例四 :汽车之家多级页面数据抓取
- ■ 示例五 :电影天堂二级页面抓取案例 md5加密后保存在数据库后用于判断是否已经爬过的数据。
- ■ requests模块
- ■ 增量爬虫Redis
- ■ 互联网图片抓取
- ■ Chrome浏览器插件
- ■ xpath
- ■ lxml解析库
- ■ 代理IP地址
- ■ Json解析模块
- ■ selenium+phantomjs/Chrome/Firefox
- ■ Scrapy框架
- ■ 中间件
- ■ 多线程爬虫
- ■ 机器视觉
- ■ 极限滑块验证码破解
- ■ 移动端数据抓取
■ 控制台抓包
1、打开浏览器,F12打开控制台,找到Network选项卡
2、控制台常用选项
2.1、Network: 抓取网络数据包
1、ALL: 抓取所有的网络数据包
2、XHR:抓取异步加载的网络数据包
3、JS : 抓取所有的JS文件
2、Sources: 格式化输出并打断点调试JavaScript代码,助于分析爬虫中一些参数
3、Console: 交互模式,可对JavaScript中的代码进行测试
3、抓取具体网络数据包后
3.1、单击左侧网络数据包地址,进入数据包详情,查看右侧
3.2、右侧:
1、Headers: 整个请求信息
General、Response Headers、Request Headers、Query String、Form Data
2、Preview: 对响应内容进行预览
3、Response:响应内容
■ 爬虫分类
■ 1. 通用网络爬虫:(搜索引擎使用,遵守robots协议)
■ robots协议(君子协议)
robots协议:通过robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取
网页后面加 robots.txt 查看网站robots协议。
实例一:www.qq.com/robots.txt
■ 2. 聚集网络爬虫:自己写的爬虫程序
■ urllib.request(请求模块)
作用: 向网站发送请求,即:我们平时在浏览器输入地址访问网站一样。
函数 | 作用 | 参数 |
---|---|---|
urllib.request.urlopen(URL,timeout) | 作用 | URL:需要爬取的URL地址 timeout:设置等待超时时间,指定时间内未响应抛出超时异常。 |
urllib.request.Request() | 包装请求,重构User-Agent,使用程序更新正常人类请求 | URL:请求的URL地址 headers:添加请求头,类型为字典headers= {‘User-Agent’:} |
1、bytes = response.read() # read()得到结果为 bytes 数据类型
2、string = response.read().decode() # decode() 转为 string 数据类型
3、url = response.geturl() # 返回实际数据的URL地址
4、code = response.getcode() # 返回HTTP响应码
# 补充
5、string.encode() # bytes -> string
6、bytes.decode() # string -> bytes
■ 1. urlopen.py 打开浏览器,输入百度地址(http://www.baidu.com/),得到百度的响应
import urllib.request
# urlopen() : 向URL发请求,返回响应对象
response=urllib.request.urlopen('http://www.baidu.com/')
# 提取响应内容
html = response.read().decode('utf-8')
# 打印响应内容
print(html)
■ User-Agent
作用: User-Agent 有游览器,操作系统信息。
■ 1. 测试网站: http://httpbin.org/get 发送请求,会返回我们的请求头User-Agent内容。
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
■ 2. 写的py代码的User-Agent:是Python-urllib/3.7,这样子很容易被服务器知道你是爬虫访问的,所以在发送请求前指定一个User-Agent
'''向http://httpbin.org/get请求,并得到响应'''
import urllib.request
# 得到: 响应对象
res = urllib.request.urlopen('http://httpbin.org/get')
# 获取响应内容
html = res.read().decode()
# 返回实际数据的URL地址
url = res.geturl()
# 返回HTTP响应码
code = res.getcode()
print(html)
==输出结果为如下: 重点是 “User-Agent”: “Python-urllib/3.9”, ==
{
"args": {},
"headers": {
"Accept-Encoding": "identity",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.9",
"X-Amzn-Trace-Id": "Root=1-66459722-1898192e214c238340a291e8"
},
"origin": "120.229.89.12",
"url": "http://httpbin.org/get"
}
■ 3. 包装User-Agent,这样服务器就会觉得你是正常访问
import urllib.request
url = 'http://httpbin.org/get'
# 1.创建请求对象
req = urllib.request.Request(
url=url,
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0'}
)
# 2.发请求获取响应对象
res = urllib.request.urlopen(req)
# 3.提取响应对象内容
html = res.read().decode()
print(html)
==输出结果为如下: 重点是 “User-Agent”: “Mozilla/5.0”, ==
{
"args": {},
"headers": {
"Accept-Encoding": "identity",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0",
"X-Amzn-Trace-Id": "Root=1-664597b1-3331b21109723b253d37e8ca"
},
"origin": "120.229.89.12",
"url": "http://httpbin.org/get"
}
■ 4. from useragents import ua_list 自动获取 User-Agent
import random
from useragents import ua_list
req = request.Request(
url=url,
headers={'User-Agent':random.choice(ua_list)}
)
res = request.urlopen(req)
html = res.read().decode('utf-8','ignore')
return html
■ urllib.parse(URL地址编码模块)
■ 1. 简介
作用:给URL地址中查询参数进行编码
编码前:https://www.baidu.com/s?wd=美女
编码后:https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3
# 模块名
urllib.parse
# 导入
import urllib.parse
from urllib import parse
■ 2. urllib.parse.urlencode({dict}) 编码
■ 2.1 URL地址中一个查询参数
# 查询参数:{'wd' : '美女'}
# urlencode编码后:'wd=%e7%be%8e%e5%a5%b3'
# 示例代码
query_string = {'wd' : '美女'}
result = urllib.parse.urlencode(query_string)
# result: 'wd=%e7%be%8e%e5%a5%b3'
■ 2.2 URL地址中多个查询参数
from urllib import parse
query_string_dict = {
'wd' : '美女',
'pn' : '50'
}
params = parse.urlencode(query_string_dict)
url = 'http://www.baidu.com/s?{}'.format(params)
print(url) # http://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3&pn=50
■ 2.3 拼接URL地址的3种方式 (+, %s, format())
# 1、字符串相加
baseurl = 'http://www.baidu.com/s?'
params = 'wd=%E7XXXX&pn=20'
url = baseurl + params
print(url) # http://www.baidu.com/s?wd=%E7XXXX&pn=20
# 2、字符串格式化(占位符)
params = 'wd=%E7XXXX&pn=20'
url = 'http://www.baidu.com/s?%s'% params
print(url) # http://www.baidu.com/s?wd=%E7XXXX&pn=20
# 3、format()方法
url = 'http://www.baidu.com/s?{}'
params = 'wd=#E7XXXX&pn=20'
url = url.format(params)
print(url) # http://www.baidu.com/s?wd=%E7XXXX&pn=20
■ 2.4 拼接url地址发送请求保存html到本地文件
from urllib import request,parse
# 1.拼url地址
# 'http://www.baidu.com/s?wd=??'
url = 'http://www.baidu.com/s?{}'
word = input('请输入搜索内容:')
params = parse.urlencode({'wd':word})
full_url = url.format(params)
# 2.发请求保存到本地
# 1.创建请求对象-Request
# 2.获取响应对象-urlopen
# 3.获取响应内容-readxxxx
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
req = request.Request(url=full_url,headers=headers)
res = request.urlopen(req)
html = res.read().decode()
# 保存到本地文件
filename = word + '.html'
with open(filename,'w') as f:
f.write(html)
■ 3. urllib.parse.quote(‘中文’)
■ 3.1 parse.quote() 编码示例
from urllib import request,parse
# 1.拼接url地址
# 'http://www.baidu.com/s?wd=??'
url = 'http://www.baidu.com/s?wd={}'
word = input('请输入搜索内容:')
params = parse.quote(word)
full_url = url.format(params)
# 2.发请求保存到本地
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
req = request.Request(url=full_url,headers=headers) # 创建请求对象-Request
res = request.urlopen(req) # 获取响应对象-urlopen
html = res.read().decode() # 获取响应内容-readxxxx
# 3.保存到本地文件
filename = word + '.html'
with open(filename,'w',encoding='utf-8') as f: # 由于网站是encoding='utf-8' 我们打开又是GB2312编码这样内容有中文就会乱码
f.write(html)
■ 示例一:抓取输入名字百度贴吧的几页的html
from urllib import request,parse
import time
import random
from useragents import ua_list
class TiebaSpider(object):
def __init__(self):
self.url = 'http://tieba.baidu.com/f?{}'
# 请求
def get_html(self,url):
req = request.Request(
url=url,
headers={'User-Agent':random.choice(ua_list)}
)
res = request.urlopen(req)
html = res.read().decode('utf-8','ignore')
return html
# 解析
def parse_html(self):
pass
# 保存
def save_html(self,filename,html):
with open(filename,'w',encoding='utf-8') as f:
f.write(html)
# 入口函数
def run(self):
name = input('请输入贴吧名:')
begin = int(input('请输入起始页:'))
stop = int(input('请输入终止页:'))
# 拼接地址,发请求
for page in range(begin,stop+1):
pn = (page-1)*50
params = {
'kw' : name,
'pn' : str(pn)
}
params = parse.urlencode(params) # 对字典进行编码
url = self.url.format(params)
html = self.get_html(url)
filename = '{}-第{}页.html'.format(name,page)
self.save_html(filename,html)
# 提示
print('第%d页抓取成功' % page)
# 每爬取1个页面随机休眠1-3秒钟
time.sleep(random.randint(1,3))
time.sleep(random.uniform(0,1))
if __name__ == '__main__':
start = time.time()
spider = TiebaSpider()
spider.run()
end = time.time()
print('执行时间:%.2f' % (end-start))
■ 示例二 :猫眼电影-榜单-top100榜
from urllib import request
import re
import time
import random
from useragents import ua_list
import csv
class MaoyanSpider(object):
def __init__(self):
self.url = 'https://maoyan.com/board/4?offset={}'
def get_html(self,url):
headers = {'User-Agent':random.choice(ua_list)}
req = request.Request(url=url,headers=headers)
res = request.urlopen(req)
html = res.read().decode()
# 直接解析
self.parse_html(html)
def parse_html(self,html):
re_bds = '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?class="releasetime">(.*?)</p>'
pattern = re.compile(re_bds,re.S)
# r_list: [('大话西游','周星驰','1994'),(),()]
r_list = pattern.findall(html)
self.save_html(r_list)
# writerow()实现
# def save_html(self,r_list):
# with open('maoyan.csv','a') as f:
# writer = csv.writer(f)
# for r in r_list:
# name = r[0].strip()
# star = r[1].strip()[3:]
# #上映时间:1994-09-10(加拿大)
# time = r[2].strip()[5:15]
# L = [name,star,time]
# writer.writerow(L)
# print(name,time,star)
# writerows()实现 - [(),(),()]
def save_html(self, r_list):
L = []
with open('maoyan.csv', 'a') as f:
writer = csv.writer(f)
for r in r_list:
name = r[0].strip()
star = r[1].strip()[3:]
# 上映时间:1994-09-10(加拿大)
time = r[2].strip()[5:15]
L.append((name,star,time))
print(name, time, star)
# 在for循环外面
writer.writerows(L)
def run(self):
for offset in range(0,31,10):
url = self.url.format(offset)
self.get_html(url)
time.sleep(random.uniform(1,2))
if __name__ == '__main__':
spider = MaoyanSpider()
spider.run()
■ 示例三 :猫眼获取数据保存到mongodb
from urllib import request
import re
import time
import random
from useragents import ua_list
import pymongo
class MaoyanSpider(object):
def __init__(self):
self.url = 'https://maoyan.com/board/4?offset={}'
# 3个对象
self.conn = pymongo.MongoClient(
'localhost',27017
)
self.db = self.conn['maoyandb']
self.myset = self.db['maoyanset']
def get_html(self,url):
headers = {'User-Agent':random.choice(ua_list)}
req = request.Request(url=url,headers=headers)
res = request.urlopen(req)
html = res.read().decode()
# 直接解析
self.parse_html(html)
def parse_html(self,html):
re_bds = '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?class="releasetime">(.*?)</p>'
pattern = re.compile(re_bds,re.S)
# r_list: [('大话西游','周星驰','1994'),(),()]
r_list = pattern.findall(html)
self.save_html(r_list)
# mongodb数据库: maoyandb -> maoyanset
def save_html(self, r_list):
for r in r_list:
# item定义在for循环里边
item = {}
item['name'] = r[0].strip()
item['star'] = r[1].strip()[3:]
item['time'] = r[2].strip()[5:15]
print(item)
self.myset.insert_one(item)
# insert_many([{},{},{},{}])
def run(self):
for offset in range(0,31,10):
url = self.url.format(offset)
self.get_html(url)
time.sleep(random.uniform(1,2))
if __name__ == '__main__':
spider = MaoyanSpider()
spider.run()
■ 示例四 :汽车之家多级页面数据抓取
■ 1. 分析
■ 示例五 :电影天堂二级页面抓取案例 md5加密后保存在数据库后用于判断是否已经爬过的数据。
■ 1. 领取任务
# 地址
电影天堂 - 2019年新片精品 - 更多
# 目标
电影名称、下载链接
# 分析
*********一级页面需抓取***********
1、电影详情页链接
*********二级页面需抓取***********
1、电影名称
2、电影下载链接
■ 2. 实现步骤
- 确定响应内容中是否存在所需抓取数据
- 找URL规律
第1页 :https://www.dytt8.net/html/gndy/dyzz/list_23_1.html
第2页 :https://www.dytt8.net/html/gndy/dyzz/list_23_2.html
第n页 :https://www.dytt8.net/html/gndy/dyzz/list_23_n.html
- 写正则表达式
1、一级页面正则表达式
<table width="100%".*?<td width="5%".*?<a href="(.*?)".*?ulink">.*?</table>
2、二级页面正则表达式
<div class="title_all"><h1><font color=#07519a>(.*?)</font></h1></div>.*?<td style="WORDWRAP.*?>.*?>(.*?)</a>
- 把电影天堂数据存入MySQL数据库 - 增量爬取
# 思路
# 1、MySQL中新建表 request_finger,存储所有爬取过的链接的指纹
# 2、在爬取之前,先判断该指纹是否爬取过,如果爬取过,则不再继续爬取
- 代码实现
先在命令行建库建表
# 建库建表
create database filmskydb charset utf8;
use filmskydb;
create table request_finger(
finger char(32)
)charset=utf8;
create table filmtab(
name varchar(200),
download varchar(500)
)charset=utf8;
from urllib import request
import re
from useragents import ua_list
import time
import random
import pymysql
from hashlib import md5
class FilmSkySpider(object):
def __init__(self):
# 一级页面url地址
self.url = 'https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html'
self.db = pymysql.connect('192.168.153.151', 'tiger', '123456', 'filmskydb',
charset='utf8')
self.cursor = self.db.cursor()
# 获取html功能函数
def get_html(self, url):
headers = {
'User-Agent': random.choice(ua_list)
}
req = request.Request(url=url, headers=headers)
res = request.urlopen(req)
# 通过网站查看网页源码,查看网站charset='gb2312'
# 如果遇到解码错误,识别不了一些字符,则 ignore 忽略掉
html = res.read().decode('gb2312', 'ignore')
return html
# 正则解析功能函数
def re_func(self, re_bds, html):
pattern = re.compile(re_bds, re.S)
r_list = pattern.findall(html)
return r_list
# 获取数据函数
def parse_page(self, one_url):
html = self.get_html(one_url)
re_bds = r'<table width="100%".*?<td width="5%".*?<a href="(.*?)".*?ulink">.*?</table>'
# one_page_list: ['/html/xxx','/html/xxx','/html/xxx']
one_page_list = self.re_func(re_bds, html)
for href in one_page_list:
two_url = 'https://www.dytt8.net' + href
# 生成指纹 - md5加密
s = md5()
s.update(two_url.encode())
two_url_md5 = s.hexdigest()
# 判断链接是否需要抓取
if self.is_go_on(two_url_md5):
self.parse_two_page(two_url)
# 爬取完成此链接后将指纹放到数据库表中
ins = 'insert into request_finger values(%s)'
self.cursor.execute(ins, [two_url_md5])
self.db.commit()
# uniform: 浮点数,爬取1个电影信息后sleep
time.sleep(random.uniform(1, 3))
def is_go_on(self, two_url_md5):
# 爬取之前先到数据库中查询比对
sel = 'select finger from request_finger where finger=%s'
# 开始抓取之前,先来判断该链接之前是否抓取过
result = self.cursor.execute(sel, [two_url_md5])
if not result:
return True
# 解析二级页面数据
def parse_two_page(self, two_url):
item = {}
html = self.get_html(two_url)
re_bds = r'<div class="title_all"><h1><font color=#07519a>(.*?)</font></h1></div>.*?<td style="WORD-WRAP.*?>.*?>(.*?)</a>'
# two_page_list: [('名称1','ftp://xxxx.mkv')]
two_page_list = self.re_func(re_bds, html)
item['name'] = two_page_list[0][0].strip()
item['download'] = two_page_list[0][1].strip()
ins = 'insert into filmtab values(%s,%s)'
film_list = [
item['name'], item['download']
]
self.cursor.execute(ins, film_list)
self.db.commit()
print(film_list)
def main(self):
for page in range(1, 201):
one_url = self.url.format(page)
self.parse_page(one_url)
# uniform: 浮点数
time.sleep(random.uniform(1, 3))
if __name__ == '__main__':
spider = FilmSkySpider()
spider.main()
■ requests模块
■ 1. 安装
Linux
sudo pip3 install requests
Windows
# 方法一
进入cmd命令行 :python -m pip install requests
# 方法二
右键管理员进入cmd命令行 :pip install requests
1 2 3 4
■ 2. requests.get() 向网站发起请求,并获取响应对象
# 向网站发起请求,并获取响应对象
res = requests.get(url,headers=headers)
# 参数
1、url :需要抓取的URL地址
2、headers : 请求头
3、timeout : 超时时间,超过时间会抛出异常
# 响应对象(res)属性
1、encoding :响应字符编码
res.encoding = 'utf-8'
2、text :字符串
3、content :字节流
4、status_code :HTTP响应码
5、url :实际数据的URL地址
非结构化数据保存
with open('xxx.jpg','wb') as f:
f.write(res.content)
■ 3. 保存赵丽颖图片到本地
import requests
url = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1567090051520&di=77e8b97b3280f999cf51340af4315b4b&imgtype
=jpg&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20171121%2F4e6759d153d04c6badbb0a
5262ec103d.jpeg'
headers = {'User-Agent':'Mozilla/5.0'}
html = requests.get(url=url,headers=headers).content
with open('花千骨.jpg','wb') as f:
f.write(html)
■ 4. requests.get()参数 params
import requests
baseurl = 'http://tieba.baidu.com/f?'
params = {
'kw' : '赵丽颖吧',
'pn' : '50'
}
headers = {'User-Agent' : 'Mozilla/4.0'}
# 自动对params进行编码,然后自动和url进行拼接,去发请求
res = requests.get(url=baseurl,params=params,headers=headers)
res.encoding = 'utf-8'
print(res.text)
■ 5. requests.get()参数 SSL证书认证参数-Verify
1、适用网站: https类型网站但是没有经过 证书认证机构 认证的网站
2、适用场景: 抛出 SSLError 异常则考虑使用此参数
1、verify=True(默认) : 检查证书认证
2、verify=False(常用): 忽略证书认证
# 示例
response = requests.get(
url=url,
params=params,
headers=headers,
verify=False
)
■ 5. requests.get()参数 -代理参数-proxies
■ 5.1 定义
1、定义: 代替你原来的IP地址去对接网络的IP地址。
2、作用: 隐藏自身真实IP,避免被封。
■ 5.2 获取代理IP网站
西刺代理、快代理、全网代理、代理精灵、... ...
■ 5.3 参数类型
1、语法结构
proxies = {
'协议':'协议://IP:端口号'
}
2、示例
proxies = {
'http':'http://IP:端口号',
'https':'https://IP:端口号'
}
■ 5.3 示例一: 使用免费普通代理IP访问测试网站: http://httpbin.org/get
import requests
url = 'http://httpbin.org/get'
headers = {
'User-Agent':'Mozilla/5.0'
}
#定义代理,在代理IP网站中查找免费代理IP
proxies = {
'http':'http://112.85.164.220:9999',
'https':'https://112.85.164.220:9999'
}
html = requests.get(url,proxies=proxies,headers=headers,timeout=5).text
print(html)
■ 5.3 建立一个自己的代理IP池,随时更新用来抓取网站数据
1、从西刺代理IP网站上,抓取免费代理IP
2、测试抓取的IP,可用的保存在文件中
import requests
from lxml import etree
import time
import random
from fake_useragent import UserAgent
class GetProxyIP(object):
def __init__(self):
self.url = 'https://www.xicidaili.com/nn/{}'
# 随机生成1个User-Agent
def get_headers(self):
ua = UserAgent()
useragent = ua.random
headers = {'User-Agent':useragent}
return headers
# 获取可用代理IP文件
def get_ip_file(self,url):
headers = self.get_headers()
html = requests.get(url=url,headers=headers,timeout=5).text
parse_html = etree.HTML(html)
tr_list = parse_html.xpath('//tr')
for tr in tr_list[1:]:
ip = tr.xpath('./td[2]/text()')[0]
port = tr.xpath('./td[3]/text()')[0]
# 测试ip:port是否可用
self.test_ip(ip,port)
def test_ip(self,ip,port):
proxies = {
'http':'http://{}:{}'.format(ip,port),
'https': 'https://{}:{}'.format(ip, port),
}
test_url = 'http://www.baidu.com/'
try:
res = requests.get(url = test_url,proxies = proxies,timeout = 8)
if res.status_code == 200:
print(ip,port,'Success')
with open('proxies.txt','a') as f:
f.write(ip + ':' + port + '\n')
except Exception as e:
print(ip,port,'Failed')
# 主函数
def main(self):
for i in range(1, 1001):
url = self.url.format(i)
self.get_ip_file(url)
time.sleep(random.randint(5, 10))
if __name__ == '__main__':
spider = GetProxyIP()
spider.main()
■ 5.4
import requests
class ProxyPool(object):
def __init__(self):
self.url = 'http://dev.kdlapi.com/api/getproxy/?orderid=967108906914177&num=55&protocol=2&method=2&an_an=1&an_ha=1&sep=1'
self.headers = {'User-Agent':''}
def save_proxy(self):
html = requests.get(url=self.url,headers=self.headers).text
# ip_list: ['1.1.1.1:8888','']
ip_list = html.split('\r\n')
print(ip_list)
for ip in ip_list:
# 测试ip,可用的保存到文件
if self.test_ip(ip):
# 把ip写入到文件
with open('ip.txt','a') as f:
f.write(ip + '\n')
# 测试代理ip是否可用
def test_ip(self,ip):
proxies = {
'http':'http://{}'.format(ip),
'https':'https://{}'.format(ip)
}
try:
res = requests.get(
url='http://www.baidu.com/',
proxies=proxies,
timeout=2
)
if res.status_code == 200:
print(ip,'可用')
return True
except Exception as e:
print(ip,'不可用')
return False
if __name__ == '__main__':
spider = ProxyPool()
spider.save_proxy()
■ 5.5 写一个获取收费开放代理的接口
# 获取开放代理的接口
import requests
def test_ip(ip):
url = 'http://www.baidu.com/'
proxies = {
'http':'http://{}'.format(ip),
'https':'https://{}'.format(ip),
}
try:
res = requests.get(url=url,proxies=proxies,timeout=8 )
if res.status_code == 200:
return True
except Exception as e:
return False
# 提取代理IP
def get_ip_list():
api_url = 'http://dev.kdlapi.com/api/getproxy/?orderid=946562662041898&num=100&protocol=1&method=2&an_an=1&an_ha=1&sep=2'
html = requests.get(api_url).content.decode('utf-8','ignore')
# ip_port_list: ['IP:PORT','IP:PORT','']
ip_port_list = html.split('\r\n')
# 依次遍历代理IP,并进行测试
for ip in ip_port_list:
with open('proxy_ip.txt','a') as f:
if test_ip(ip):
f.write(ip + '\n')
if __name__ == '__main__':
get_ip_list()
■ 5.6 私密代理
1、语法结构
proxies = {
'协议':'协议://用户名:密码@IP:端口号'
}
2、示例
proxies = {
'http':'http://用户名:密码@IP:端口号',
'https':'https://用户名:密码@IP:端口号'
}
示例代码
import requests
url = 'http://httpbin.org/get'
proxies = {
'http': 'http://309435365:szayclhp@106.75.71.140:16816',
'https':'https://309435365:szayclhp@106.75.71.140:16816',
}
headers = {
'User-Agent' : 'Mozilla/5.0',
}
html = requests.get(url,proxies=proxies,headers=headers,timeout=5).text
print(html)
■ 6. requests.get()参数 -cookie 抓取需要登录才能访问的页面
抓取需要登录才能访问的页面
cookie和session机制
http协议为无连接协议
cookie: 存放在客户端浏览器
session: 存放在Web服务器
■ 6.1 方法一 人人网登录案例 -登录网站手动抓取Cookie
1、先登录成功1次,获取到携带登录信息的Cookie
登录成功 - 个人主页 - F12抓包 - 刷新个人主页 - 找到主页的包(profile)
2、携带着cookie发请求
** Cookie
** User-Agent
# 1、将self.url改为 个人主页的URL地址
# 2、将Cookie的值改为 登录成功的Cookie值
# (.*): (.*)
# "$1": "$2",
# //*[@id="operate_area"]/div[1]/ul/li[1]/span
import requests
from lxml import etree
class RenrenLogin(object):
def __init__(self):
self.url = 'http://www.renren.com/969255813/profile'
self.headers = {
"Cookie": "td_cookie=18446744071755925920; anonymid=k1u1d9w1-74iox1; depovince=GW; _r01_=1; JSESSIONID=abcB2p2gp7PgCepRLxx3w; ick_login=21331dc6-741c-48b0-9bc0-2b108f6537ad; first_login_flag=1; ln_uact=18633615542; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; jebe_key=9c4bdeee-d396-4774-9804-a9ec189e321a%7C2e9beece3ead42fe6a26739d515f14df%7C1571276385847%7C1%7C1571276390161; jebe_key=9c4bdeee-d396-4774-9804-a9ec189e321a%7C2e9beece3ead42fe6a26739d515f14df%7C1571276385847%7C1%7C1571276390164; wp_fold=0; td_cookie=18446744071756139140; jebecookies=ba19300e-2925-4b13-b8af-d21ee45da052|||||; _de=2229A2704041535FC5E7FC3B0F076082; p=db307493030c61b1e1b3b498a780655b3; t=4fe365d1adf8179ea16550ae0b895aab3; societyguester=4fe365d1adf8179ea16550ae0b895aab3; id=969255813; xnsid=28993c4d; ver=7.0; loginfrom=null",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36",
}
def parse_html(self):
html = requests.get(
url=self.url,
headers=self.headers
).text
p = etree.HTML(html)
xpath_bds = '//*[@id="operate_area"]/div[1]/ul/li[1]/span/text()'
r_list = p.xpath(xpath_bds)
print(r_list)
if __name__ == '__main__':
spider = RenrenLogin()
spider.parse_html()
■ 6.2 方法二 把抓取到的cookie处理为字典 使用requests.get()中的参数:cookies
处理cookie为字典
# 处理cookies为字典
cookies_dict = {}
cookies = 'xxxx'
for kv in cookies.split('; ')
cookies_dict[kv.split('=')[0]] = kv.split('=')[1]
import requests
from lxml import etree
class RenrenLogin(object):
def __init__(self):
self.url = 'http://www.renren.com/967469305/profile'
self.headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
# 获取字典形式cookie的函数
def get_cookie_dict(self):
cookie_dict = {}
# 自己抓到的cookie
cookies = 'xxxxxxx'
for kv in cookies.split('; '):
# kv: 'td_cookie=184xxx'
key = kv.split('=')[0]
value = kv.split('=')[1]
cookie_dict[key] = value
return cookie_dict
def get_html(self):
# 获取cookies
cookies = self.get_cookie_dict()
html = requests.get(
url=self.url,
headers=self.headers,
cookies=cookies,
).text
self.parse_html(html)
def parse_html(self,html):
parse_html = etree.HTML(html)
r_list = parse_html.xpath('//*[@id="operate_area"]/div[1]/ul/li[1]/span/text()')
print(r_list)
if __name__ == '__main__':
spider = RenrenLogin()
spider.get_html()
}
■ 6.3 方法一 requests模块处理Cookie
# 把Formdata中的 email 和 password 的改为自己真实的用户名和密码
import requests
from lxml import etree
class RenrenSpider(object):
def __init__(self):
self.post_url = 'http://www.renren.com/PLogin.do'
self.get_url = 'http://www.renren.com/967469305/profile'
# 实例化session对象
self.session = requests.session()
def get_html(self):
# email和password为<input>节点中name的属性值
form_data = {
'email' : 'xxxx',
'password' : 'xxxx'
}
# 先session.post()
self.session.post(url=self.post_url,data=form_data)
# 再session.get()
html = self.session.get(url=self.get_url).text
self.parse_html(html)
def parse_html(self,html):
parse_html = etree.HTML(html)
r_list = parse_html.xpath('//li[@class="school"]/span/text()')
print(r_list)
if __name__ == '__main__':
spider = RenrenSpider()
spider.get_html()
■ 7 requests.post()参数
Post类型请求的网站
■ 7.1 参数-data
response = requests.post(url,data=data,headers=headers)
# data :post数据(Form表单数据-字典格式)
■ 7.2 请求方式的特点
# 一般
GET请求 : 参数在URL地址中有显示
POST请求: Form表单提交数据
■ 7.4 有道翻译破解案例(post)
import requests
import time
import random
from hashlib import md5
class YdSpider(object):
def __init__(self):
# 1.url一定要写F12抓到的POST的地址: Request URL
self.url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
self.headers = {
# 2.检查频率最高的三个
"Cookie": "OUTFOX_SEARCH_USER_ID=584508170@10.108.160.19; OUTFOX_SEARCH_USER_ID_NCOO=415742579.8667161; JSESSIONID=aaa6xixEY8dfdcuUIHo3w; ___rl__test__cookies=1571131223483",
"Referer": "http://fanyi.youdao.com/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36",
}
self.proxies = {
'http': 'http://309435365:szayclhp@123.56.246.33:16816',
'https': 'https://309435365:szayclhp@123.56.246.33:16816'
}
# 获取ts,salt,sign
def get_ts_salt_sign(self,word):
ts = str(int(time.time()*1000))
salt = ts + str(random.randint(0,9))
string = "fanyideskweb" + word + salt + "n%A-rKaT5fb[Gy?;N5@Tj"
s = md5()
s.update(string.encode())
sign = s.hexdigest()
return ts,salt,sign
def attack(self,word):
ts,salt,sign = self.get_ts_salt_sign(word)
# form表单数据
data = {
"i": word,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": salt,
"sign": sign,
"ts": ts,
"bv": "5d4cb17cceb9ecd02ece3ed9923d3a7a",
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTlME",
}
# 此处为post请求,一定使用 reqeusts.post()方法
html = requests.post(
url=self.url,
data=data,
headers=self.headers,
proxies=self.proxies
).json()
print('翻译结果:',html['translateResult'][0][0]['tgt'])
def run(self):
word = input('请输入要翻译的单词:')
self.attack(word)
if __name__ == '__main__':
spider = YdSpider()
spider.run()
■ 7.5 民政部网站数据抓取
import requests
from lxml import etree
import re
class GovSpider(object):
def __init__(self):
self.url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/'
self.headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
'Cookie':'td_cookie=18446744071602793018; td_cookie=18446744071601712718; _gscu_190942352=711200480urfj316; _gscbrs_190942352=1; td_cookie=18446744071602559600; wzws_cid=7c25b6f33e355504f8779f50aed809a99f6c76ad8aa92c93a43d8c6f1eab82a8deba674257edf01f29378319c08ade1f67e5d099d66adab79554be470a97d993; _gscs_190942352=t71122459w1kg4p19|pv:4'
}
self.proxies = {
'http': 'http://309435365:szayclhp@123.56.246.33:16816',
'https': 'https://309435365:szayclhp@123.56.246.33:16816'
}
# 获取最新链接
def get_link(self):
one_html = requests.get(url=self.url,headers=self.headers,proxies=self.proxies).content.decode()
# xpath提取最新链接
p = etree.HTML(one_html)
link_list = p.xpath('//a[@class="artitlelist"]/@href')
link = link_list[1] if link_list else None
if link:
# link为假链接
link = 'http://www.mca.gov.cn' + link
# 通过假链接link来提取真链接
self.get_real_link(link)
else:
print('提取链接失败')
# 提取真实链接
def get_real_link(self,link):
html = requests.get(
url=link,
proxies=self.proxies,
headers=self.headers
).content.decode()
# 正则解析提取
re_bds = 'window.location.href="(.*?)"'
p = re.compile(re_bds,re.S)
real_link = p.findall(html)[0]
# 提取数据
self.parse_html(real_link)
# 提取数据
def parse_html(self,real_link):
two_html = requests.get(url=real_link,headers=self.headers).text
p = etree.HTML(two_html)
# 基准xpath: 节点对象列表
tr_list = p.xpath('//tr[@height="19"]')
for tr in tr_list:
name = tr.xpath('./td[3]/text()')[0].strip()
code = tr.xpath('./td[2]/text()')[0].strip()
print(name,code)
# 入口函数
def run(self):
self.get_link()
if __name__ == '__main__':
spider = GovSpider()
spider.run()
■ 7.6 动态加载数据抓取-Ajax
■ 7.7 豆瓣电影数据抓取案例
import requests
import json
from fake_useragent import UserAgent
import re
class DoubanSpider(object):
def __init__(self):
self.url = 'https://movie.douban.com/j/chart/top_list?'
self.i = 0
def parse_html(self,params):
html = requests.get(
url=self.url,
params=params,
headers={ 'User-Agent':UserAgent().random }
).text
# json.loads(): 把json数据->Python数据类型
html = json.loads(html)
# 提取数据
item = {}
for film in html:
item['name'] = film['title']
item['score'] = film['score']
print(item)
self.i += 1
def run(self):
type_dict = self.get_all()
menu = ''
for key in type_dict.keys():
# key: '剧情' '喜剧'
menu += ' {} '.format(key)
print(menu)
name = input('请输入电影类别:')
# 得到了type的值
typ = type_dict[name]
total = self.get_total(typ)
# 100个电影 range(0,100,20)
for page in range(0,total,20):
params = {
'type': typ, # 电影类型
'interval_id': '100:90',
'action': '',
'start': str(page), # 每次加载电影的起始索引值 0 20 40 60
'limit': '20' # 每次加载的电影数量
}
self.parse_html(params)
print('电影总数:',self.i)
def get_all(self):
url = 'https://movie.douban.com/chart'
html = requests.get(
url=url,
headers={'User-Agent':UserAgent().random}
).text
p = re.compile('<a href=".*?type_name=(.*?)&type=(.*?)&.*?</a>',re.S)
r_list = p.findall(html)
# [('剧情','5'),('喜剧','24')]
type_dict = {}
for r in r_list:
type_dict[r[0]] = r[1]
return type_dict
def get_total(self,typ):
url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(typ)
html = requests.get(
url=url,
headers={ 'User-Agent':UserAgent().random }
).json()
total = html['total']
return total
if __name__ == '__main__':
spider = DoubanSpider()
spider.run()
■ 增量爬虫Redis
■ 1. 原理
■ 互联网图片抓取
■ 示例一: 通过链接获取图片,抓取下来,保存在本地
"""
通过链接获取图片,抓取下来,保存在本地
"""
import requests
image_url = 'https://cbu01.alicdn.com/img/ibank/O1CN016VtvDr1iK2kLm5l0R_!!933764393-0-cib.jpg'
# headers = {'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0'}
# 1, content属性:获取bytes数据类型
html = requests.get(url=image_url).content
# 2. 保存到本地文
# filename = image_url[-10:] # 截取最后10位数据作为文件名称保存
# print(filename)
# with open(filename ,'wb') as f:
with open('meitu.jpg' ,'wb') as f:
f.write(html)
■ 示例二:使用os 获取图片,抓取下来,保存到images文件夹中
"""
使用os 获取图片,抓取下来,保存images文件夹中
"""
import requests
import os
image_url = 'https://cbu01.alicdn.com/img/ibank/O1CN016VtvDr1iK2kLm5l0R_!!933764393-0-cib.jpg'
# headers = {'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0'}
# 1, content属性:获取bytes数据类型
html = requests.get(url=image_url).content
# 2. 确保图片保存路径
directory = './images/'
if not os.path.exists(directory):
os.makedirs(directory)
# 3. 保存到本地文
filename = directory+image_url[-10:] # 截取最后10位数据作为文件名称保存
print(filename)
with open(filename,'wb') as f:
f.write(html)
■ 示例三:百度图片练习代码实现,创建目录,准备保存图片
import requests
import re
from urllib import parse
import os
class BaiduImageSpider(object):
def __init__(self):
self.url = 'https://image.baidu.com/search/index?tn=baiduimage&word={}'
self.headers = {'User-Agent':'Mozilla/5.0'}
# 获取图片
def get_image(self,url,word):
html = requests.get(url,headers=self.headers).text
pattern = re.compile('"hoverURL":"(.*?)"',re.S)
img_link_list = pattern.findall(html)
# 创建目录,准备保存图片
directory = 'E:\\{}\\'.format(word)
if not os.path.exists(directory):
os.makedirs(directory)
i = 1
for img_link in img_link_list:
filename = '{}{}_{}.jpg'.format(directory, word, i)
self.save_image(img_link,filename)
i += 1
def save_image(self,img_link,filename):
html = requests.get(url=img_link,headers=self.headers).content
with open(filename,'wb') as f:
f.write(html)
print(filename,'下载成功')
def run(self):
word = input('你要谁的照片:')
word_parse = parse.quote(word)
url = self.url.format(word)
self.get_image(url,word)
if __name__ == '__main__':
spider = BaiduImageSpider()
spider.run()
■ Chrome浏览器插件
1、Xpath Helper: 轻松获取HTML元素的xPath路径
# 开启/关闭: Ctrl + Shift + x
2、Proxy SwitchyOmega: Chrome浏览器中的代理管理扩展程序
3、JsonView: 格式化输出json格式数据
■ xpath
■ 1. 简介
XPath即为XML路径语言,它是一种用来确定XML文档中某部分位置的语言,同样适用于HTML文档的检索
■ 2. 选取节点
1、// :从所有节点中查找(包括子节点和后代节点)
2、@ :获取属性值
# 使用场景1(属性值作为条件)
//div[@class="movie-item-info"]
# 使用场景2(直接获取属性值)
//div[@class="movie-item-info"]/a/img/@src
■ 3. 匹配多路径(或)
xpath表达式1 | xpath表达式2 | xpath表达式3
■ 4. 常用函数
1、contains() :匹配属性值中包含某些字符串节点
# 查找id属性值中包含字符串 "car_" 的 li 节点
//li[contains(@id,"car_")]
2、text() :获取节点的文本内容
# 查找所有汽车的价格
//li/p[@class="price"]/text()
■ 5. 匹配演示
<ul class="CarList">
<li class="bjd" id="car_001" href="http://www.bjd.com/">
<p class="name">布加迪</p>
<p class="model">威航</p>
< p class ="price" > 2500万 </ p>
< p class ="color" > 红色 </ p>
</ li>
<li class ="byd" id="car_002" href="http://www.byd.com/">
<p class ="name" > 比亚迪 </ p>
<p class ="model" > 秦 </ p>
<p class ="price" > 15万 </ p>
<p class ="color" > 白色 </ p>
</ li>
</ ul>
1、查找所有的li节点
//li
2、获取所有汽车的名称: 所有li节点下的子节点p的值 (class属性值为name)
//li/p[@class="name"]
3、找比亚迪车的信息: 获取ul节点下第2个li节点的汽车信息
//ul/li[2]
4、获取所有汽车的链接: ul节点下所有li子节点的href属性的值
//ul/li/@href
# 只要涉及到条件,加 []
# 只要获取属性值,加 @
■ lxml解析库
■ 1. 安装
Ubantu安装: sudo pip3 install lxml
Window安装: python -m pip install lxml
■ 2. 使用流程
1、导模块
from lxml import etree
2、创建解析对象
parse_html = etree.HTML(html)
3、解析对象调用xpath
r_list = parse_html.xpath('xpath表达式')
■ 3. 示例一:lxml + xpath
from lxml import etree
html = '''
<div class="wrapper">
<a href="/" id="channel">新浪社会</a>
<ul id="nav">
<li>
<a href="http://domestic.sina.com/" title="国内">国内</a>
</li>
<li><a href="http://world.sina.com/" title="国际">国际</a></li>
<li><a href="http://mil.sina.com/" title="军事">军事</a></li>
<li><a href="http://photo.sina.com/" title="图片">图片</a></li>
<li><a href="http://society.sina.com/" title="社会">社会</a></li>
<li><a href="http://ent.sina.com/" title="娱乐">娱乐</a></li>
<li><a href="http://tech.sina.com/" title="科技">科技</a></li>
<li><a href="http://sports.sina.com/" title="体育">体育</a></li>
<li><a href="http://finance.sina.com/" title="财经">财经</a></li>
<li><a href="http://auto.sina.com/" title="汽车">汽车</a></li>
</ul>
</div>
'''
parse_html = etree.HTML(html)
xpath_bds = '//ul[@id="nav"]//a/text()'
r_list = parse_html.xpath(xpath_bds)
print(r_list) # ['国内', '国际', '军事', '图片', '社会', '娱乐', '科技', '体育', '财经', '汽车']
# 获取所有a节点 href 的属性值 ['/','https://xxx']
xpath_bds = '//a/@href'
r_list = parse_html.xpath(xpath_bds)
print(r_list)
# 获取所有a节点 href 的属性值,但是不包含 /
xpath_bds = '//ul[@id="nav"]/li/a/@href'
r_list = parse_html.xpath(xpath_bds)
print(r_list)
# 获取 国际、国内、军事...,但是不包含 新浪社会
xpath_bds = '//ul[@id="nav"]/li/a/text()'
r_list = parse_html.xpath(xpath_bds)
print(r_list)
# 输出结果
['国内', '国际', '军事', '图片', '社会', '娱乐', '科技', '体育', '财经', '汽车']
['/', 'http://domestic.sina.com/', 'http://world.sina.com/', 'http://mil.sina.com/', 'http://photo.sina.com/', 'http://society.sina.com/', 'http://ent.sina.com/', 'http://tech.sina.com/', 'http://sports.sina.com/', 'http://finance.sina.com/', 'http://auto.sina.com/']
['http://domestic.sina.com/', 'http://world.sina.com/', 'http://mil.sina.com/', 'http://photo.sina.com/', 'http://society.sina.com/', 'http://ent.sina.com/', 'http://tech.sina.com/', 'http://sports.sina.com/', 'http://finance.sina.com/', 'http://auto.sina.com/']
['国内', '国际', '军事', '图片', '社会', '娱乐', '科技', '体育', '财经', '汽车']
■ 4. 示例二:xpath
import requests
from lxml import etree
class MaoyanSpider(object):
def __init__(self):
self.url = 'https://maoyan.com/board/4'
self.headers = { 'User-Agent':'' }
def save_html(self):
html = requests.get(url=self.url,headers=self.headers).text
# 解析
parse_html = etree.HTML(html)
# 基准xpath,大的节点对象列表
dd_list = parse_html.xpath('//dl[@class="board-wrapper"]/dd')
item = {}
for dd in dd_list:
item['name'] = dd.xpath('.//p[@class="name"]/a/@title')[0].strip()
item['star'] = dd.xpath('.//p[@class="star"]/text()')[0].strip()
item['time'] = dd.xpath('.//p[@class="releasetime"]/text()')[0].strip()
print(item)
def run(self):
self.save_html()
if __name__ == '__main__':
spider = MaoyanSpider()
spider.run()
输出结果:
{'name': '我不是药神', 'star': '主演:徐峥,王传君,周一围', 'time': '上映时间:2018-07-05'}
{'name': '肖申克的救赎', 'star': '主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿', 'time': '上映时间:1994-09-10(加拿大)'}
{'name': '海上钢琴师', 'star': '主演:蒂姆·罗斯,比尔·努恩 ,克兰伦斯·威廉姆斯三世', 'time': '上映时间:2019-11-15'}
{'name': '绿皮书', 'star': '主演:维果·莫腾森,马赫沙拉·阿里,琳达·卡德里尼', 'time': '上映时间:2019-03-01'}
{'name': '霸王别姬', 'star': '主演:张国荣,张丰毅,巩俐', 'time': '上映时间:1993-07-26'}
{'name': '美丽人生', 'star': '主演:罗伯托·贝尼尼,朱斯蒂诺·杜拉诺,赛尔乔·比尼·布斯特里克', 'time': '上映时间:2020-01-03'}
{'name': '这个杀手不太冷', 'star': '主演:让·雷诺,加里·奥德曼,娜塔莉·波特曼', 'time': '上映时间:1994-09-14(法国)'}
{'name': '星际穿越', 'star': '主演:马修·麦康纳,安妮·海瑟薇,杰西卡·查斯坦', 'time': '上映时间:2014-11-12'}
{'name': '小偷家族', 'star': '主演:中川雅也,安藤樱,松冈茉优', 'time': '上映时间:2018-08-03'}
{'name': '怦然心动', 'star': '主演:玛德琳·卡罗尔,卡兰·麦克奥利菲,艾丹·奎因', 'time': '上映时间:2010-07-26(美国)'}
■ 5. 链家房产数据抓取
import requests
from lxml import etree
import time
import random
from fake_useragent import UserAgent
class LianjiaSpider(object):
def __init__(self):
self.url = 'https://bj.lianjia.com/ershoufang/pg{}/'
self.blag = 1
# 随机headers
def get_headers(self):
agent = UserAgent().random
headers = { 'User-Agent':agent }
return headers
# 请求函数
def get_html(self,url):
if self.blag <= 3:
try:
res = requests.get(
url,
headers=self.get_headers(),
timeout=5
)
html = res.content.decode()
return html
except Exception as e:
print('Retry')
self.blag += 1
self.get_html(url)
# 解析提取数据
def parse_html(self,url):
html = self.get_html(url)
# html要么为正常内容,要么为None
if html:
p = etree.HTML(html)
# 基准xpath表达式 - 30个房源节点对象列表
h_list = p.xpath('//ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]')
for h in h_list:
item = {}
# 名称
name_list = h.xpath('.//a[@data-el="region"]/text()')
item['name'] = name_list[0] if name_list else None
# 户型+面积+方位+精装
info_list = h.xpath('.//div[@class="houseInfo"]/text()') # ['三室 | 92 | ']
if info_list:
L = info_list[0].split('|')
if len(L) == 5:
item['model'] = L[1].strip()
item['area'] = L[2].strip()
item['direction'] = L[3].strip()
item['perfect'] = L[4].strip()
else:
item['model'] = item['area'] = item['direction'] = item['perfect'] = None
else:
item['model'] = item['area'] = item['direction'] = item['perfect'] = None
# 楼层+区域+总价+单价
floor_list = h.xpath('.//div[@class="positionInfo"]/text()')
item['floor'] = floor_list[0].strip() if floor_list else None
address_list = h.xpath('.//div[@class="positionInfo"]/a/text()')
item['address'] = address_list[0].strip() if address_list else None
total_list = h.xpath('.//div[@class="totalPrice"]/span/text()')
item['total'] = total_list[0].strip() if total_list else None
unit_list = h.xpath('.//div[@class="unitPrice"]/span/text()')
item['unit'] = unit_list[0].strip() if unit_list else None
print(item)
# 入口函数
def run(self):
for i in range(1,101):
url = self.url.format(i)
self.parse_html(url)
time.sleep(random.randint(1,3))
# 每抓取1页要初始化self.blag
self.blag = 1
if __name__ == '__main__':
spider = LianjiaSpider()
spider.run()
■ 6. 百度贴吧图片下载 lxml + xpath
import requests
from lxml import etree
import time
import random
from urllib import parse
class BaiduImageSpider(object):
def __init__(self):
self.url = 'http://tieba.baidu.com/f?'
# IE的User-Agent返回数据最标准
# 如果各种检查后数据下不来,考虑使用IE的User-Agent尝试
self.headers = { 'User-Agent':'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3)' }
# 功能函数 - 获取html
def get_html(self,url,params=None):
html = requests.get(
url=url,
params=params,
headers=self.headers
).content.decode('utf-8','ignore')
return html
# 功能函数2 - xpath解析
def xpath_func(self,html,xpath_bds):
p = etree.HTML(html)
r_list = p.xpath(xpath_bds)
return r_list
# 解析+提取
def parse_html(self,one_url,params):
one_html = self.get_html(one_url,params)
xpath_bds = '//div[@class="t_con cleafix"]/div/div/div/a/@href'
# t_list: ['/p/2323','/p/2323222']
t_list = self.xpath_func(one_html,xpath_bds)
for t in t_list:
t_link = 'http://tieba.baidu.com' + t
# 保存图片
self.save_image(t_link)
# 给定1个帖子链接,把帖子中所有图片下载到本地
def save_image(self,t_link):
t_html = self.get_html(t_link)
# 图片+视频xpath,使用xpath的或: 图片xpath | 视频xpath
xpath_bds = '//div[@class="d_post_content j_d_post_content clearfix"]/img[@class="BDE_Image"]/@src | //div[@class="video_src_wrapper"]/embed/@data-video'
# img_list: ['src1','src2','src3']
img_list = self.xpath_func(t_html,xpath_bds)
for img in img_list:
img_html = requests.get(
url=img,
headers=self.headers
).content
filename = img[-10:]
with open(filename,'wb') as f:
f.write(img_html)
print('%s下载成功' % filename)
time.sleep(random.uniform(0,2))
def run(self):
name = input('请输入贴吧名:')
begin = int(input('请输入起始页:'))
end = int(input('请输入终止页:'))
for page in range(begin,end+1):
pn = (page-1)*50
params = {
'kw':name,
'pn':str(pn)
}
self.parse_html(self.url,params)
if __name__ == '__main__':
spider = BaiduImageSpider()
spider.run()
■ 代理IP地址
■ 1. 简介
■ 2.
■ 3.
■ Json解析模块
■ 1. json.loads(json)
把json格式的字符串转为Python数据类型
html_json = json.loads(res.text)
■ 2. json.dump(python,f,ensure_ascii=False)
把python数据类型 转为 json格式的字符串 一般让你把抓取的数据保存为json文件时使用
第1个参数: python类型的数据(字典,列表等)
第2个参数: 文件对象
第3个参数: ensure_ascii=False # 序列化时编码
■ 示例一 将集合转换成json 写入文件中
import json
item = {'name':'QQ','app_id':1}
with open('小米.json','a') as f:
json.dump(item,f,ensure_ascii=False)
结果如下:
{"name": "QQ", "app_id": 1}
■ 示例二 将列表转换成json 写入文件中
import json
item_list = []
for i in range(3):
item = {'name':'QQ','id':i}
item_list.append(item)
with open('xiaomi.json','a') as f:
json.dump(item_list,f,ensure_ascii=False)
结果如下:
[{"name": "QQ", "id": 0}, {"name": "QQ", "id": 1}, {"name": "QQ", "id": 2}]
■ 3. json.dumps(python) 把 python 变量类型 转为 json 类型
将item 类型转换成json类型
import json
# json.dumps()之前
item = {'name':'QQ','app_id':1}
print('before dumps',type(item)) # dict
# json.dumps之后
item = json.dumps(item)
print('after dumps',type(item)) # str
输出结果:
before dumps <class 'dict'>
after dumps <class 'str'>
■ 4. json.load(f) 将json文件读取,并转为python类型
import json
with open('D:\\spider_test\\xiaomi.json','r') as f:
data = json.load(f)
print(data)
■ selenium+phantomjs/Chrome/Firefox
■ 1. 特点
1、简单,无需去详细抓取分析网络数据包,使用真实浏览器
2、需要等待页面元素加载,需要时间,效率低
■ 2. 安装
1、下载、解压
2、添加到系统环境变量
# windows: 拷贝到Python安装目录的Scripts目录中
# Linux : 拷贝到/usr/bin目录中
3、Linux中修改权限
# sudo -i
# cd /usr/bin/
# chmod +x phantomjs
改权限前: rwxr--r--
改权限后: rwxr-xr-x
■ 3. 使用流程
from selenium import webdriver
# 1、创建浏览器对象
browser = webdriver.Firefox(executable_path='/xxx/geckodriver')
# 2、输入网址
browser.get('URL')
# 3、查找节点
brower.find_xxxx
# 4、做对应操作
element.send_keys('')
element.click()
# 5、关闭浏览器
browser.quit()
■ 4 重要知识点
1、browser.page_source
2、browser.page_source.find('')
3、node.send_keys('')
4、node.click()
5、find_element AND find_elements
6、browser.execute_script('javascript')
7、browser.quit()
■ 5. chromedriver设置无界面模式
from selenium import webdriver
options = webdriver.ChromeOptions()
# 添加无界面参数
options.add_argument('--headless')
browser = webdriver.Chrome(options=options)
browser.get('http://www.baidu.com/')
browser.save_screenshot('baidu.png')
■ 6. Selenium- Web自动化测试工具
■ 6. 1 定义
Web自动化测试工具,可运行在浏览器,根据指令操作浏览器
只是工具,必须与第三方浏览器结合使用
■ 6. 2 安装
Linux: sudo pip3 install selenium
Windows: python -m pip install selenium
■ 6. 3 selenium - 键盘操作
from selenium.webdriver.common.keys import Keys
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')
# 1、在搜索框中输入"selenium"
browser.find_element_by_id('kw').send_keys('赵丽颖')
# 2、输入空格
browser.find_element_by_id('kw').send_keys(Keys.SPACE)
# 3、Ctrl+a 模拟全选
browser.find_element_by_id('kw').send_keys(Keys.CONTROL, 'a')
# 4、Ctrl+c 模拟复制
browser.find_element_by_id('kw').send_keys(Keys.CONTROL, 'c')
# 5、Ctrl+v 模拟粘贴
browser.find_element_by_id('kw').send_keys(Keys.CONTROL, 'v')
# 6、输入回车,代替 搜索 按钮
browser.find_element_by_id('kw').send_keys(Keys.ENTER)
■ 6. 4 selenium - 鼠标操作
from selenium import webdriver
# 导入鼠标事件类
from selenium.webdriver import ActionChains
driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')
#移动到 设置,perform()是真正执行操作,必须有
element = driver.find_element_by_xpath('//*[@id="u1"]/a[8]')
ActionChains(driver).move_to_element(element).perform()
#单击,弹出的Ajax元素,根据链接节点的文本内容查找
driver.find_element_by_link_text('高级搜索').click()
■ 6. 5 selenium - 切换页面
页面中点开链接出现新的页面,但是浏览器对象browser还是之前页面的对象
# 获取当前所有句柄(窗口)
all_handles = browser.window_handles
# 切换browser到新的窗口,获取新窗口的对象
browser.switch_to.window(all_handles[1])
■ 6. 6 selenium - iframe子框架
网页中嵌套了网页,先切换到iframe子框架,然后再执行其他操作
browser.switch_to.iframe(iframe_element)
■ 6. 6.1 示例 - 登录qq邮箱
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get('https://mail.qq.com/')
# 切换到iframe子框架
login_frame = driver.find_element_by_id('login_frame')
driver.switch_to.frame(login_frame)
# 用户名+密码+登录
driver.find_element_by_id('u').send_keys('qq账号')
driver.find_element_by_id('p').send_keys('qq密码')
driver.find_element_by_id('login_button').click()
■ 7. phantomjs 无界面浏览器
定义
无界面浏览器(又称无头浏览器),在内存中进行页面加载,高效
Windows安装(phantomjs、chromedriver、geckodriver)
■ 8. phantomjs、chromedriver、geckodrive
■ 8.1 Windows安装
1、下载对应版本的phantomjs、chromedriver、geckodriver
2、把chromedriver.exe拷贝到python安装目录的Scripts目录下(添加到系统环境变量)
# 查看python安装路径: where python
3、验证
cmd命令行: chromedriver
# 下载地址
1、chromedriver : 下载对应版本
http://npm.taobao.org/mirrors/chromedriver/ 失效
[添加链接描述](https://developer.chrome.com/docs/chromedriver/downloads?hl=zh-cn)
[下载链接描述](https://googlechromelabs.github.io/chrome-for-testing/)
2、geckodriver
https://github.com/mozilla/geckodriver/releases
3、phantomjs
https://phantomjs.org/download.html
■ 8.2 Linux 安装
1、下载后解压
tar -zxvf geckodriver.tar.gz
2、拷贝解压后文件到 /usr/bin/ (添加环境变量)
sudo cp geckodriver /usr/bin/
3、更改权限
sudo -i
cd /usr/bin/
chmod 777 geckodriver
■ 8. 示例代码一:使用 selenium+浏览器 打开百度
# 导入seleinum的webdriver接口
from selenium import webdriver
import time
# 创建浏览器对象
browser = webdriver.PhantomJS()
browser.get('http://www.baidu.com/')
time.sleep(5)
# 关闭浏览器
browser.quit()
■ 9. 示例代码二:打开百度,搜索赵丽颖,点击搜索,查看
from selenium import webdriver
import time
# 1.创建浏览器对象 - 已经打开了浏览器
browser = webdriver.Chrome()
# 2.输入: http://www.baidu.com/
browser.get('http://www.baidu.com/')
# 3.找到搜索框,向这个节点发送文字: 赵丽颖
browser.find_element_by_xpath('//*[@id="kw"]').send_keys('赵丽颖')
# 4.找到 百度一下 按钮,点击一下
browser.find_element_by_xpath('//*[@id="su"]').click()
■ 10 浏览器对象(browser)方法
# from selenium import webdriver
browser = webdriver.Chrome(executable_path='path')
browser.get(url)
browser.page_source # HTML结构源码
browser.page_source.find('字符串')
# 从html源码中搜索指定字符串,没有找到返回:-1
browser.quit() # 关闭浏览器
■ 11. 定位节点
■ 11.1 单元素查找(1个节点对象)
browser.find_element_by_id('')
browser.find_element_by_name('')
browser.find_element_by_class_name('')
browser.find_element_by_xpath('')
■ 11.2 多元素查找([节点对象列表])
browser.find_elements_by_id('')
browser.find_elements_by_name('')
browser.find_elements_by_class_name('')
browser.find_elements_by_xpath('')
■ 11.3 节点对象操作
ele.send_keys('') # 搜索框发送内容
ele.click()
ele.text # 获取文本内容,包含子节点和后代节点的文本内容
ele.get_attribute('src') # 获取属性值
■ 11.3 京东爬虫案例
执行JS脚本,获取动态加载数据
browser.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'
)
from selenium import webdriver
import time
import pymongo
class JdSpider(object):
def __init__(self):
self.url = 'https://www.jd.com/'
# 设置无界面模式
self.options = webdriver.ChromeOptions()
self.options.add_argument('--headless')
self.browser = webdriver.Chrome(options=self.options)
# 计数
self.i = 0
# 3个对象
self.conn = pymongo.MongoClient(
'127.0.0.1',27017
)
self.db = self.conn['jddb']
self.myset = self.db['jdset']
# 输入地址+输入商品+点击按钮
def get_html(self):
self.browser.get(self.url)
self.browser.find_element_by_xpath('//*[@id="key"]').send_keys('爬虫书')
self.browser.find_element_by_xpath('//*[@id="search"]/div/div[2]/button').click()
time.sleep(2)
# 把进度条拉到最底部+提取商品信息
def get_data(self):
# 拉动进度条
self.browser.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'
)
# 给页面元素加载预留时间
time.sleep(3)
# 提取数据
li_list = self.browser.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li')
for li in li_list:
item = {}
item['name'] = li.find_element_by_xpath('.//div[@class="p-name p-name-type-2"]/a/em').text.strip()
item['price'] = li.find_element_by_xpath('.//div[@class="p-price"]').text.strip()
item['commit'] = li.find_element_by_xpath('.//div[@class="p-commit"]/strong').text.strip()
item['shop'] = li.find_element_by_xpath('.//div[@class="p-shop"]').text.strip()
print(item)
# 存入mongodb数据库
self.myset.insert_one(item)
self.i += 1
def run(self):
# 此方法一定只执行一次
self.get_html()
while True:
self.get_data()
# class: pn-next
# class: pn-next disabled
if self.browser.page_source.find('pn-next disabled') == -1:
self.browser.find_element_by_class_name('pn-next').click()
# 给元素加载预留时间
time.sleep(1)
else:
print('数量:',self.i)
break
if __name__ == '__main__':
spider = JdSpider()
spider.run()
■ Scrapy框架
■ 1 Scrapy-定义
异步处理框架,可配置和可扩展程度非常高,Python中使用最广泛的爬虫框架
■ 2 Scrapy-安装
# Ubuntu安装
1、安装依赖包
1、sudo apt-get install libffi-dev
2、sudo apt-get install libssl-dev
3、sudo apt-get install libxml2-dev
4、sudo apt-get install python3-dev
5、sudo apt-get install libxslt1-dev
6、sudo apt-get install zlib1g-dev
7、sudo pip3 install -I -U service_identity
2、安装scrapy框架
1、sudo pip3 install Scrapy
# Windows安装
cmd命令行(管理员): python -m pip install Scrapy
# Error: Microsoft Visual C++ 14.0 is required xxx
■ 3 Scrapy-框架五大组件
1、引擎(Engine) :整个框架核心
2、调度器(Scheduler) :维护请求队列
3、下载器(Downloader):获取响应对象
4、爬虫文件(Spider) :数据解析提取
5、项目管道(Pipeline):数据入库处理
**********************************
# 下载器中间件(Downloader Middlewares) : 引擎->下载器,包装请求(随机代理等)
# 蜘蛛中间件(Spider Middlewares) : 引擎->爬虫文件,可修改响应对象属性
■ 4 scrapy-爬虫工作流程
# 爬虫项目启动
1、由引擎向爬虫程序索要第一个要爬取的URL,交给调度器去入队列
2、调度器处理请求后出队列,通过下载器中间件交给下载器去下载
3、下载器得到响应对象后,通过蜘蛛中间件交给爬虫程序
4、爬虫程序进行数据提取:
1、数据交给管道文件去入库处理
2、对于需要继续跟进的URL,再次交给调度器入队列,依次循环
■ 5 scrapy-常用命令
# 1、创建爬虫项目
scrapy startproject 项目名
# 2、创建爬虫文件
scrapy genspider 爬虫名 域名
# 3、运行爬虫
scrapy crawl 爬虫名
■ 6 scrapy-项目目录结构
Baidu # 项目文件夹
├── Baidu # 项目目录
│ ├── items.py # 定义数据结构
│ ├── middlewares.py # 中间件
│ ├── pipelines.py # 数据处理
│ ├── settings.py # 全局配置
│ └── spiders
│ ├── baidu.py # 爬虫文件
└──
scrapy.cfg # 项目基本配置文件
■ 7 scrapy-全局配置文件settings.py详解
# 1、定义User-Agent
USER_AGENT = 'Mozilla/5.0'
# 2、是否遵循robots协议,一般设置为False
ROBOTSTXT_OBEY = False
# 3、最大并发量,默认为16
CONCURRENT_REQUESTS = 32
# 4、下载延迟时间
DOWNLOAD_DELAY = 1
# 5、请求头,此处也可以添加User-Agent
DEFAULT_REQUEST_HEADERS={}
# 6、项目管道
ITEM_PIPELINES={
'项目目录名.pipelines.类名':300
}
■ 8 scrapy-创建爬虫项目步骤
1、新建项目 :scrapy startproject 项目名
2、cd 项目文件夹
3、新建爬虫文件 :scrapy genspider 文件名 域名
4、明确目标(items.py)
5、写爬虫程序(文件名.py)
6、管道文件(pipelines.py)
7、全局配置(settings.py)
8、运行爬虫 :scrapy crawl 爬虫名
■ 9 scrapy-pycharm运行爬虫项目
1、创建begin.py(和scrapy.cfg文件同目录)
2、begin.py中内容:
from scrapy import cmdline
cmdline.execute('scrapy crawl maoyan'.split())
■ 10 示例一:打开百度首页,把 ‘百度一下,你就知道’ 抓取下来,从终端输出
■ 10.1 创建项目Baidu 和 爬虫文件baidu
1、scrapy startproject Baidu
2、cd Baidu
3、scrapy genspider baidu www.baidu.com
■ 10.2 编写爬虫文件baidu.py,xpath提取数据
# -*- coding: utf-8 -*-
import scrapy
class BaiduSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['www.baidu.com']
start_urls = ['http://www.baidu.com/']
def parse(self, response):
result = response.xpath('/html/head/title/text()').extract_first()
print('*'*50)
print(result)
print('*'*50)
■ 10.3 全局配置settings.py
USER_AGENT = 'Mozilla/5.0'
ROBOTSTXT_OBEY = False
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
■ 10.4 创建run.py(和scrapy.cfg同目录)
from scrapy import cmdline
cmdline.execute('scrapy crawl baidu'.split())
■ 10.5 启动爬虫
直接运行 run.py 文件即可
■ 11 示例二:
■ 12 示例三:
■ 中间件
■ 1.
■ 2.
■ 3.
■ 多线程爬虫
■ 1. 队列
# 导入模块
from queue import Queue
# 使用
q = Queue()
q.put(url)
q.get() # 当队列为空时,阻塞
q.empty() # 判断队列是否为空,True/False
■ 2. 线程模块
# 导入模块
from threading import Thread
# 使用流程
t = Thread(target=函数名) # 创建线程对象
t.start() # 创建并启动线程
t.join() # 阻塞等待回收线程
# 如何创建多线程
t_list = []
for i in range(5):
t = Thread(target=函数名)
t_list.append(t)
t.start()
for t in t_list:
t.join()
■ 3. 线程锁
# 注意多线程写入的线程锁问题
from threading import Lock
lock = Lock()
# 加锁
lock.acquire()
python语句
# 释放锁
lock.release()
■ 4. 小米应用商店抓取(多线程)
import requests
import json
from threading import Thread,Lock
from queue import Queue
import time
import csv
import re
class XiaomiSpider(object):
def __init__(self):
self.url = 'http://app.mi.com/categotyAllListApi?page={}&categoryId={}&pageSize=30'
self.headers = {'User-Agent':''}
# 创建url队列,存放所有待爬取的URL地址
self.q = Queue()
self.f = open('xiaomi.csv','a')
self.lock = Lock()
self.writer = csv.writer(self.f)
# 计数
self.i = 1
# 获取所有类别及code
def get_all_type(self):
url = 'http://app.mi.com/'
html = requests.get(url=url,headers=self.headers).text
p = re.compile('<a href="/category/(.*?)">(.*?)</a>',re.S)
# r_list: [(2,'聊天社交'),(),()]
r_list = p.findall(html)
for r in r_list:
# 遍历一个类别,就要把这个类别的所有页put到队列中
self.url_in(r)
# 总页数
def get_total(self,code):
url = self.url.format(0,code)
html = requests.get(url=url,headers=self.headers).json()
count = html['count']
if count % 30 == 0:
total = count // 30
else:
total = (count // 30) + 1
return total
# url入队列
def url_in(self,r):
# 获取此类别总页数
total = self.get_total(r[0])
for page in range(total):
url = self.url.format(page,r[0])
self.q.put(url)
# 线程事件函数
def parse_html(self):
while True:
if not self.q.empty():
url = self.q.get()
html = requests.get(url=url,headers=self.headers).json()
app_list = []
for app in html['data']:
name = app['displayName']
app_list.append((name,))
print(name)
self.lock.acquire()
self.i += 1
self.lock.release()
# 加锁+释放锁
self.lock.acquire()
self.writer.writerows(app_list)
self.lock.release()
time.sleep(0.1)
else:
break
# 入口函数
def run(self):
# url地址入队列
self.get_all_type()
t_list = []
for i in range(5):
t = Thread(target=self.parse_html)
t_list.append(t)
t.start()
for t in t_list:
t.join()
if __name__ == '__main__':
start = time.time()
spider = XiaomiSpider()
spider.run()
end = time.time()
print('数量:',spider.i)
print('执行时间:%.2f' % (end-start))
■ 5. 多级页面多线程抓取- 腾讯招聘数据抓取
import requests
import json
import time
from urllib import parse
class TencentSpider(object):
def __init__(self):
self.one_url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1571206111698&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword={}&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
self.two_url = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1571206506767&postId={}&language=zh-cn'
self.headers = {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
# 打开文件
self.f = open('tencent.json','w')
self.job_list = []
def parse_html(self,url):
one_html = requests.get(
url=url,
headers=self.headers
).json()
# 提取postId,拼接二级页面地址
for one in one_html['Data']['Posts']:
# postId ,two_url
postid = one['PostId']
two_url = self.two_url.format(postid)
self.get_data(two_url)
time.sleep(0.1)
def get_data(self,two_url):
html = requests.get(
url=two_url,
headers=self.headers
).json()
job = {}
job['name'] = html['Data']['RecruitPostName']
job['duty'] = html['Data']['Responsibility']
job['require'] = html['Data']['Requirement']
# 所有数据都添加都字典job中
self.job_list.append(job)
print(job)
def run(self):
keyword = input('请输入关键字:')
keyword = parse.quote(keyword)
total_page = self.get_total_page(keyword)
for page in range(1,total_page+1):
url = self.one_url.format(keyword,page)
self.parse_html(url)
# 存储到json文件中
json.dump(self.job_list,self.f,ensure_ascii=False)
# 关闭文件
self.f.close()
# 获取总页数
def get_total_page(self,keyword):
url = self.one_url.format(keyword,1)
html = requests.get(url=url,headers=self.headers).json()
count = html['Data']['Count']
if count % 10 == 0:
total_page = count // 10
else:
total_page = (count // 10) + 1
return total_page
if __name__ == '__main__':
spider = TencentSpider()
spider.run()