python爬虫之基础
爬虫基础知识
python基础
1、Python 编写爬虫程序的流程:
先由 urllib 模块的 request 方法打开 URL 得到网页 HTML 对象。 -- 请求网页
使用浏览器打开网页源代码分析网页结构以及元素节点。 -- 获取数据
通过 Beautiful Soup 或则正则表达式提取数据。 -- 解析数据
存储数据到本地磁盘或数据库。 -- 保存数据
难点:登录与会话保持
面向对象的代码结构:
# 程序结构
class xxxSpider(object):
def __init__(self):
# 定义常用变量,比如url或计数变量等
def get_html(self):
# 获取响应内容函数,使用随机User-Agent
def parse_html(self):
# 使用正则表达式来解析页面,提取数据
def write_html(self):
# 将提取的数据按要求保存,csv、MySQL数据库等
def run(self):
# 主函数,用来控制整体逻辑
if __name__ == '__main__':
# 程序开始运行时间
spider = xxxSpider()
spider.run()
2、熟悉网络构成
HTML、css、js
3、静态网页、动态网页
静态网页的数据全部包含在 HTML 中。
动态网页指的是采用了动态网页技术的页面, 网页可以局部更新,可以异步加载。
4、抓包工具 Fiddler
################爬虫库############################
5、爬虫库 urllib
1) urlopen()
表示向网站发起请求并获取响应对象,如下所示:
urllib.request.urlopen(url,timeout)
urlopen() 有两个参数,说明如下:
url:表示要爬取数据的 url 地址。
timeout:设置等待超时时间,指定时间内未得到响应则抛出超时异常。
2) Request()
该方法用于创建请求对象、包装请求头,比如重构 User-Agent(即用户代理,指用户使用的浏览器)使程序更像人类的请求,而非机器。重构 User-Agent 是爬虫和反爬虫斗争的第一步。在下一节会做详细介绍。
urllib.request.Request(url,headers)
参数说明如下:
url:请求的URL地址。
headers:重构请求头。
3) html响应对象方法
bytes = response.read() # read()返回结果为 bytes 数据类型
string = response.read().decode() # decode()将字节串转换为 string 类型
url = response.geturl() # 返回响应对象的URL地址
code = response.getcode() # 返回请求时的HTTP响应码
4) 编码解码操作
#字符串转换为字节码
string.encode("utf-8")
#字节码转换为字符串
bytes.decode("utf-8")
6、User-Agent
随机获取UA:pip install fake-useragent
from fake_useragent import UserAgent
#实例化一个对象
ua=UserAgent()
#随机获取一个ie浏览器ua
print(ua.ie)
print(ua.ie)
#随机获取一个火狐浏览器ua
print(ua.firefox)
print(ua.firefox)
7、爬取网页
from urllib import request
from urllib import parse
# 拼接URL地址
def get_url(word):
url = 'http://www.baidu.com/s?{}'
#此处使用urlencode()进行编码
params = parse.urlencode({'wd':word})
url = url.format(params)
return url
# 发请求,保存本地文件
def request_url(url,filename):
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
# 请求对象 + 响应对象 + 提取内容
req = request.Request(url=url,headers=headers)
res = request.urlopen(req)
html = res.read().decode('utf-8')
# 保存文件至本地
with open(filename,'w',encoding='utf-8') as f:
f.write(html)
# 主程序入口
if __name__ == '__main__':
word = input('请输入搜索内容:')
url = get_url(word)
filename = word + '.html'
request_url(url,filename)
8、爬取贴吧
from urllib import request,parse
import time
import random
from ua_info import ua_list #使用自定义的ua池
#定义一个爬虫类
class TiebaSpider(object):
#初始化url属性
def __init__(self):
self.url='http://tieba.baidu.com/f?{}'
# 1.请求函数,得到页面,传统三步
def get_html(self,url):
req=request.Request(url=url,headers={'User-Agent':random.choice(ua_list)})
res=request.urlopen(req)
#windows会存在乱码问题,需要使用 gbk解码,并使用ignore忽略不能处理的字节
#linux不会存在上述问题,可以直接使用decode('utf-8')解码
html=res.read().decode("gbk","ignore")
return html
# 2.解析函数,此处代码暂时省略,还没介绍解析模块
def parse_html(self):
pass
# 3.保存文件函数
def save_html(self,filename,html):
with open(filename,'w') as f:
f.write(html)
# 4.入口函数
def run(self):
name=input('输入贴吧名:')
begin=int(input('输入起始页:'))
stop=int(input('输入终止页:'))
# +1 操作保证能够取到整数
for page in range(begin,stop+1):
pn=(page-1)*50
params={
'kw':name,
'pn':str(pn)
}
#拼接URL地址
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-2秒钟的时间
time.sleep(random.randint(1,2))
#以脚本的形式启动爬虫
if __name__=='__main__':
start=time.time()
spider=TiebaSpider() #实例化一个对象spider
spider.run() #调用入口函数
end=time.time()
#查看程序执行时间
print('执行时间:%.2f'%(end-start)) #爬虫执行时间
9、正则表达式
python的re模块
1) re.compile()
该方法用来生成正则表达式对象,其语法格式如下:
regex=re.compile(pattern,flags=0)
参数说明:
pattern:正则表达式对象。
flags:代表功能标志位,扩展正则表达式的匹配。
2) re.findall()
根据正则表达式匹配目标字符串内容。
re.findall(pattern,string,flags=0)
该函数的返回值是匹配到的内容列表,如果正则表达式有子组,则只能获取到子组对应的内容。参数说明如下:
pattern:正则表达式对象。
string:目标字符串
flags:代表功能标志位,扩展正则表达式的匹配。
3) regex.findall()
该函数根据正则表达式对象匹配目标字符串内容。其语法格式如下:
regex.findall(string,pos,endpos)
参数说明:
string 目标字符串。
pos 截取目标字符串的开始匹配位置。
endpos 截取目标字符串的结束匹配位置。
4) re.split()
该函数使用正则表达式匹配内容,切割目标字符串。返回值是切割后的内容列表。参数说明:
re.split(pattern,string,flags = 0)
参数说明:
pattern:正则表达式。
string:目标字符串。
flags:功能标志位,扩展正则表达式的匹配。
5) re.sub
该函数使用一个字符串替换正则表达式匹配到的内容。返回值是替换后的字符串。其语法格式如下:
re.sub(pattern,replace,string,max,flags = 0)
其参数说明:
pattern:正则表达式。
replace:替换的字符串。
string:目标字符串。
max:最多替换几处,默认替换全部,
flags:功能标志位,扩展正则表达式的匹配。
5) re.search()
匹配目标字符串第一个符合的内容,返回值为匹配的对象。语法格式如下:
re.search(pattern,string,flags=0)
参数说明:
pattern:正则表达式
string:目标字符串
10、CSV读写
CSV文件写入
1) csv.writer()
csv 模块中的 writer 类可用于读写序列化的数据,其语法格式如下:
writer(csvfile, dialect='excel', **fmtparams)
参数说明:
csvfile:必须是支持迭代(Iterator)的对象,可以是文件(file)对象或者列表(list)对象。
dialect:编码风格,默认为 excel 的风格,也就是使用逗号,分隔。
fmtparam:格式化参数,用来覆盖之前 dialect 对象指定的编码风格。
示例如下:
import csv
# 操作文件对象时,需要添加newline参数逐行写入,否则会出现空行现象
with open('eggs.csv', 'w', newline='') as csvfile:
# delimiter 指定分隔符,默认为逗号,这里指定为空格
# quotechar 表示引用符
# writerow 单行写入,列表格式传入数据
spamwriter = csv.writer(csvfile, delimiter=' ',quotechar='|')
spamwriter.writerow(['www.biancheng.net'] * 5 + ['how are you'])
spamwriter.writerow(['hello world', 'web site', 'www.biancheng.net'])
eggs.csv 文件内容如下:
www.biancheng.net www.biancheng.net www.biancheng.net www.biancheng.net www.biancheng.net |how are you|
|hello world| |web site| www.biancheng.net
其中,quotechar 是引用符,当一段话中出现分隔符的时候,用引用符将这句话括起来,以能排除歧义。
如果想同时写入多行数据,需要使用 writerrows() 方法,代码如下所示:
import csv
with open('aggs.csv', 'w', newline='') as f:
writer = csv.writer(f)
# 注意传入数据的格式为列表元组格式
writer.writerows([('hello','world'), ('I','love','you')])
2) csv.DictWriter()
当然也可使用 DictWriter 类以字典的形式读写数据,使用示例如下:
import csv
with open('names.csv', 'w', newline='') as csvfile:
#构建字段名称,也就是key
fieldnames = ['first_name', 'last_name']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
# 写入字段名,当做表头
writer.writeheader()
# 多行写入
writer.writerows([{'first_name': 'Baked', 'last_name': 'Beans'},{'first_name': 'Lovely', 'last_name': 'Spam'}])
# 单行写入
writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})
CSV文件读取
1) csv,reader()
csv 模块中的 reader 类和 DictReader 类用于读取文件中的数据,其中 reader() 语法格式如下:
csv.reader(csvfile, dialect='excel', **fmtparams)
应用示例如下:
import csv
with open('eggs.csv', 'r', newline='') as csvfile:
spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
for row in spamreader:
print(', '.join(row))
2) csv.DictReader()
应用示例如下:
import csv
with open('names.csv', newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
print(row['first_name'], row['last_name'])
11、 爬取猫眼
from urllib import request
import re
import time
import random
import csv
from ua_info import ua_list
# 定义一个爬虫类
class MaoyanSpider(object):
# 初始化
# 定义初始页面url
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: [('我不是药神','徐峥,周一围,王传君','2018-07-05'),...] 列表元组
r_list = pattern.findall(html)
self.save_html(r_list)
# 保存数据函数,使用python内置csv模块
def save_html(self,r_list):
#生成文件对象
with open('maoyan.csv','a',newline='',encoding="utf-8") as f:
#生成csv操作对象
writer = csv.writer(f)
#整理数据
for r in r_list:
name = r[0].strip()
star = r[1].strip()[3:]
# 上映时间:2018-07-05
# 切片截取时间
time = r[2].strip()[5:15]
L = [name,star,time]
# 写入csv文件
writer.writerow(L)
print(name,time,star)
# 主函数
def run(self):
#抓取第一页数据
for offset in range(0,11,10):
url = self.url.format(offset)
self.get_html(url)
#生成1-2之间的浮点数
time.sleep(random.uniform(1,2))
# 以脚本方式启动
if __name__ == '__main__':
#捕捉异常错误
try:
spider = MaoyanSpider()
spider.run()
except Exception as e:
print("错误:",e)
12、爬取猫眼,存储到数据库
# coding=gbk
from urllib import request
import re
import time
import random
from ua_info import ua_list
import pymysql
class MaoyanSpider(object):
def __init__(self):
#初始化属性对象
self.url = 'https://maoyan.com/board/4?offset={}'
#数据库连接对象
self.db = pymysql.connect(
'localhost','root','123456','maoyandb',charset='utf8')
#创建游标对象
self.cursor = self.db.cursor()
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 = pattern.findall(html)
self.save_html(r_list)
def save_html(self, r_list):
L = []
sql = 'insert into movieinfo values(%s,%s,%s)'
# 整理数据
for r in r_list:
t = (
r[0].strip(),
r[1].strip()[3:],
r[2].strip()[5:15]
)
L.append(t)
print(L)
# 一次性插入多条数据 L:[(),(),()]
try:
self.cursor.executemany(sql,L)
# 将数据提交数据库
self.db.commit()
except:
# 发生错误则回滚
self.db.rollback()
def run(self):
for offset in range(0,11,10):
url = self.url.format(offset)
self.get_html(url)
time.sleep(random.uniform(1,3))
# 断开游标与数据库连接
self.cursor.close()
self.db.close()
if __name__ == '__main__':
start=time.time()
spider = MaoyanSpider()
spider.run()
end=time.time()
print("执行时间:%.2f" % (end-start))
13、电影天堂
# -*- coding: utf-8 -*-
from urllib import request
import re
import time
import random
import pymysql
from hashlib import md5
from ua_info import ua_list
import sys
class MovieSkySpider(object):
def __init__(self):
self.url = 'https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html'
self.db = pymysql.connect(
'localhost','root','123456','movieskydb',
charset='utf8'
)
self.cursor = self.db.cursor()
# 1.请求函数
def get_html(self, url):
headers = {'User-Agent': random.choice(ua_list)}
req = request.Request(url=url, headers=headers)
res = request.urlopen(req)
# 本网站使用gb2312的编码格式
html = res.read().decode('gb2312', 'ignore')
return html
# 2.正则解析函数
def re_func(self,re_bds,html):
pattern = re.compile(re_bds,re.S)
r_list = pattern.findall(html)
return r_list
# 3.提取数据函数
def parse_html(self,one_url):
# 调用请求函数,获取一级页面
one_html = self.get_html(one_url)
re_bds = '<table width="100%".*?<td width="5%".*?<a href="(.*?)".*?ulink">.*?</table>'
# 获取二级页面链接
# link_list: ['/html//html/gndy/dyzz/20210226/61131.html','/html/xxx','','']
link_list = self.re_func(re_bds,one_html)
for link in link_list:
# 判断是否需要爬取此链接
# 1.获取指纹
# 拼接二级页面url
two_url = 'https://www.dytt8.net' + link
s = md5()
#加密url,需要是字节串
s.update(two_url.encode())
# 生成指纹,获取十六进制加密字符串,
finger = s.hexdigest()
# 2.通过函数判断指纹在数据库中是否存在
if self.is_hold_on(finger):
# 抓取二级页面数据
self.save_html(two_url)
time.sleep(random.randint(1,2))
# 抓取后,把想用的url专属指纹存入数据库
ins = 'insert into request_finger values (%s)'
self.cursor.execute(ins,[finger])
self.db.commit()
else:
sys.exit('更新完成')
# 4.判断链接是否已经抓取过
def is_hold_on(self,finger):
# 查询数据库
sql='select finger from request_finger where finger=%s'
# execute()函数返回值为受影响的行数(即0或者非0)
r = self.cursor.execute(sql,[finger])
# 如果为0表示没有抓取过
if not r:
return True
# 5.解析二级页面,获取数据(名称与下载链接)
def save_html(self,two_url):
two_html = self.get_html(two_url)
re_bds = '<div class="title_all"><h1><font color=#07519a>(.*?)</font></h1> \
</div>.*?<a.*?href="(.*?)".*?>.*?style="BACKGROUND-COLOR:.*?</a>'
# film_list: [('name','downloadlink'),(),(),()]
film_list = self.re_func(re_bds,two_html)
print(film_list)
# 插入数据库
sql = 'insert into movieinfo values(%s,%s)'
#L = list(film_list[0])
self.cursor.executemany(sql,film_list)
self.db.commit()
#主函数
def run(self):
# 二级页面后四页的正则表达式略有不同,需要重新分析
for i in range(1,4):
url = self.url.format(i)
self.parse_html(url)
if __name__ == '__main__':
spider = MovieSkySpider()
spider.run()
14、requests
python -m pip install requests
1) requests.get()
该方法用于 GET 请求,表示向网站发起请求,获取页面响应对象。语法如下:
res = requests.get(url,headers=headers,params,timeout)
参数说明如下:
url:要抓取的 url 地址。
headers:用于包装请求头信息。
params:请求时携带的查询字符串参数。
timeout:超时时间,超过时间会抛出异常。
具体使用示例如下:
import requests
url = 'http://baidu.com'
response = requests.get(url)
print(response)
2) requests.post()
该方法用于 POST 请求,先由用户向目标 url 提交数据,然后服务器返回一个 HttpResponse 响应对象,语法如下:
response=requests.post(url,data={请求体的字典})
示例如下所示:
import requests
#百度翻译
url = 'https://fanyi.baidu.com'
#post请求体携带的参数,可通过开发者调试工具查看
#查看步骤:NetWork选项->Headers选项->Form Data
data = {'from': 'zh',
'to': 'en',
'query': '编程帮www.biancheng.net你好'
}
response = requests.post(url, data=data)
print(response)
15、爬取图片
# -*- coding:utf8 -*-
import requests
import re
from urllib import parse
import os
class BaiduImageSpider(object):
def __init__(self):
self.url = 'https://image.baidu.com/search/flip?tn=baiduimage&word={}'
self.headers = {'User-Agent':'Mozilla/4.0'}
# 获取图片
def get_image(self,url,word):
#使用 requests模块得到响应对象
res= requests.get(url,headers=self.headers)
# 更改编码格式
res.encoding="utf-8"
# 得到html网页
html=res.text
print(html)
#正则解析
pattern = re.compile('"hoverURL":"(.*?)"',re.S)
img_link_list = pattern.findall(html)
#存储图片的url链接
print(img_link_list)
# 创建目录,用于保存图片
directory = 'C:/Users/Administrator/Desktop/image/{}/'.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_parse)
self.get_image(url,word)
if __name__ == '__main__':
spider = BaiduImageSpider()
spider.run()
16、xpath
17、Xpath Helper
18、lxml
pip3 install lxml
19、lxml实例
# coding:utf8
import requests
from lxml import etree
from ua_info import ua_list
import random
class MaoyanSpider(object):
def __init__(self):
self.url='https://maoyan.com/board/4?offset=50'
self.headers={'User-Agent':random.choice(ua_list)}
def save_html(self):
html=requests.get(url=self.url,headers=self.headers).text
#jiexi
parse_html=etree.HTML(html)
# 基准 xpath 表达式,匹配10个<dd>节点对象
dd_list=parse_html.xpath('//dl[@class="board-wrapper"]/dd') #列表放10个dd
print(dd_list)
# .// 表示dd节点的所有子节点后代节点
# 构建item空字典将提取的数据放入其中
item={}
for dd in dd_list:
# 处理字典数据,注意xpath表达式匹配结果是一个列表,因此需要索引[0]提取数据
item['name']=dd.xpath('.//p[@class="name"]/a/text()')[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()
20、爬取链家网
#coding:utf8
import requests
import random
from lxml import etree
import time
#提供ua信息的的包
from fake_useragent import UserAgent
class LinajiaSpider(object):
def __init__(self):
self.url='https://bj.lianjia.com/ershoufang/pg{}/'
#计数,请求一个页面的次数,初始值为1
self.blog=1
# 随机取一个UA
def get_header(self):
#实例化ua对象
ua=UserAgent()
headers={'User-Agent':ua.random}
return headers
#发送请求
def get_html(self,url):
#在超时间内,对于失败页面尝试请求三次
if self.blog<=3:
try:
res=requests.get(url=url,headers=self.get_header(),timeout=3)
html=res.text
return html
except Exception as e:
print(e)
self.blog+=1
self.get_html(url)
# 解析提取数据
def parse_html(self,url):
html=self.get_html(url)
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
#户型+面积+方位+是否精装..['2室1厅 | 88.62平米 | 北 南 | 简装 | 顶层(共6层) | 2004年建 | 板楼']
info_list=h.xpath('.//div[@class="houseInfo"]/text()')
#判断列表是否为空
if info_list:
L=info_list[0].split('|')
# ['2室1厅 ', ' 88.62平米 ', ' 北 南 ', ' 简装 ', ' 顶层(共6层) ', ' 2004年建 ', ' 板楼']
if len(L) >= 5:
item['model']=L[0].strip()
item['area']=L[1].strip()
item['direction']=L[2].strip()
item['perfect']=L[3].strip()
item['floor']=L[4].strip()
#区域+总价+单价
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_list']=total_list[0].strip() if total_list else None
price_list=h.xpath('.//div[@class="unitPrice"]/span/text()')
item['price_list']=price_list[0].strip() if price_list else None
print(item)
# 入口函数
def run(self):
try:
for i in range(1,101):
url=self.url.format(i)
self.parse_html(url)
time.sleep(random.randint(1,3))
#每次抓取一页要初始化一次self.blog
self.blog=1
except Exception as e:
print('发生错误',e)
if __name__ == '__main__':
spider=LinajiaSpider()
spider.run()
21、有道翻译
#coding:utf8
import random
import time
from hashlib import md5
import requests
class YoudaoSpider(object):
def __init__(self):
# url一定要写抓包时抓到的POST请求的提交地址,但是还需要去掉 url中的“_o”,
# “_o”这是一种url反爬策略,做了页面跳转,若直接访问会返回{"errorCode":50}
self.url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
self.headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",
}
# 获取lts时间戳,salt加密盐,sign加密签名
def get_lts_salt_sign(self,word):
lts=str(int(time.time()*1000))
salt=lts+str(random.randint(0,9))
string = "fanyideskweb" + word + salt + "Tbh5E8=q6U3EXe+&L[4c@"
s=md5()
s.update(string.encode())
sign=s.hexdigest()
print(lts,salt,sign)
return lts,salt,sign
def attack_yd(self,word):
lts,salt,sign=self.get_lts_salt_sign(word)
#构建form表单数据
data={
"i": word,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": salt,
"sign": sign,
"lts": lts,
"bv": "cda1e53e0c0eb8dd4002cefc117fa588",
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTlME"
}
#使用 reqeusts.post()方法提交请求
res = requests.post(
url=self.url,
data=data,
headers=self.headers,
)
# res.json() 将json格式的字符串转为python数据类型
# 客户端与服务器数据交互以json字符串传递,因此需要将它转换为python数据类型
html=res.json()
print(html)
# 查看响应结果response html:{"translateResult":[[{"tgt":"hello","src":"你好"}]],"errorCode":0,"type":"zh-CHS2en"}
result=html["translateResult"][0][0]["tgt"]
print('翻译结果:', result)
def run(self):
try:
word=input('请输入要翻译的单词:')
self.attack_yd(word)
except Exception as e:
print(e)
if __name__ == '__main__':
spider=YoudaoSpider()
spider.run()
22、爬取豆瓣
#coding:utf8
import requests
import time
import random
import re
import json
from ua_info import ua_list
class DoubanSpider(object):
def __init__(self):
self.url = 'https://movie.douban.com/j/chart/top_list?'
self.i = 0
# 获取随机headers
def get_headers(self):
headers = {'User-Agent':random.choice(ua_list)}
return headers
# 获取页面
def get_page(self,params):
# 将json转换为 python 数据类型,并返回
html = requests.get(url=self.url,params=params,headers=self.get_headers()).text
html=json.loads(html)
self.parse_page(html)
# 解析并保存数据
def parse_page(self,html):
item = {}
# html列表类型: [{电影1},{电影2},{电影3}...]
for one in html:
# 名称 + 评分
item['name'] = one['title'].strip()
item['score'] = float(one['score'].strip())
print(item)
self.i += 1
# 获取电影总数
def total_number(self,type_number):
# F12抓包抓到的地址,type表示电影类型
url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(type_number)
headers = self.get_headers()
html = requests.get(url=url,headers=headers).json()
total = int(html['total'])
return total
# 获取所有电影的类型和对应type值
def get_all_type_films(self):
# 获取类型与类型码
url = 'https://movie.douban.com/chart'
headers = self.get_headers()
html = requests.get(url=url,headers=headers).text
re_bds = r'<a href=.*?type_name=(.*?)&type=(.*?)&.*?</a>'
pattern = re.compile(re_bds,re.S)
r_list = pattern.findall(html)
# 存放所有类型和对应类型码大字典
type_dict = {}
#定义一个选择电影类型的菜单
menu = ''
for r in r_list:
type_dict[r[0].strip()] = r[1].strip()
# 获取input的菜单,显示所有电影类型
menu += r[0].strip() + '|'
return type_dict,menu
# 主程序入口函数
def main(self):
# 获取type的值
type_dict,menu = self.get_all_type_films()
menu = menu + '\n你想了解什么类型电影:'
name = input(menu)
type_number = type_dict[name]
# 获取电影总数
total = self.total_number(type_number)
for start in range(0,(total+1),20):
#构建查询参数
params = {
'type' : type_number,
'interval_id' : '100:90',
'action' : '',
'start' : str(start),
'limit' : '20'
}
# 调用函数,传递params参数
self.get_page(params)
# 随机休眠1-3秒
time.sleep(random.randint(1,3))
print('电影总数量:%d部'%self.i )
if __name__ == '__main__':
spider = DoubanSpider()
spider.main()
23、Cookie模拟登录人人网
import requests
from lxml import etree
class RenrenLogin(object):
def __init__(self):
# 个人主页的url地址
self.url = 'http://www.renren.com/972496145/profile'
self.headers = {
# 将拷贝的cookie值放在此处
'Cookie':'anonymid=kmol2vxqgd4n0e; depovince=HEB; _r01_=1; ick_login=c577d6c0-0ec3-465a-89d0-9e2b8f23e107; taihe_bi_sdk_uid=0738130d7f4532165841f09abc596215; taihe_bi_sdk_session=6277ea795624ba1eddb2603d7fe45c85; _de=1D29BC9596B9643C92425970B59A3DAE; p=3e6989099ff75de92407b791266376095; first_login_flag=1; ln_uact=18519784236; ln_hurl=http://hdn.xnimg.cn/photos/hdn321/20191017/0945/h_main_El46_9a13000ecbe41986.jpg; t=7f25f8a4d3515786d146143f63d108b25; societyguester=7f25f8a4d3515786d146143f63d108b25; id=972496145; xnsid=9770206d; wpsid=15900539012757; ver=7.0; loginfrom=null; wp_fold=0; jebecookies=59f8dfaf-8416-4dbc-a539-016a7ae1b6c5|||||',
# 注意,useragent不能改变,否则cookie失效
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'
}
def get_html(self):
html = requests.get(url=self.url,headers=self.headers).text
self.parse_html(html)
def parse_html(self,html):
parse_html = etree.HTML(html)
r_school = parse_html.xpath('//*[@id="operate_area"]/div[1]/ul/li[1]/span/text()')
print(r_school)
r_birthday = parse_html.xpath('//li[@class="birthday"]/span/text()')
print(r_birthday)
home_info=parse_html.xpath('//*[@id="operate_area"]/div[1]/ul/li/text()')
item = {}
item['hometown'] = home_info[2].strip()
item['address'] = home_info[3].strip()
print(item)
if __name__ == '__main__':
spider = RenrenLogin()
spider.get_html()
24、多线程爬虫
# -*- coding:utf8 -*-
import requests
from threading import Thread
from queue import Queue
import time
from fake_useragent import UserAgent
from lxml import etree
import csv
from threading import Lock
import json
class XiaomiSpider(object):
def __init__(self):
self.url = 'http://app.mi.com/categotyAllListApi?page={}&categoryId={}&pageSize=30'
# 存放所有URL地址的队列
self.q = Queue()
self.i = 0
# 存放所有类型id的空列表
self.id_list = []
# 打开文件
self.f = open('XiaomiShangcheng.csv','a',encoding='utf-8')
self.writer = csv.writer(self.f)
# 创建锁
self.lock = Lock()
def get_cateid(self):
# 请求
url = 'http://app.mi.com/'
headers = { 'User-Agent': UserAgent().random}
html = requests.get(url=url,headers=headers).text
# 解析
parse_html = etree.HTML(html)
xpath_bds = '//ul[@class="category-list"]/li'
li_list = parse_html.xpath(xpath_bds)
for li in li_list:
typ_name = li.xpath('./a/text()')[0]
typ_id = li.xpath('./a/@href')[0].split('/')[-1]
# 计算每个类型的页数
pages = self.get_pages(typ_id)
#往列表中添加二元组
self.id_list.append( (typ_id,pages) )
# 入队列
self.url_in()
# 获取count的值并计算页数
def get_pages(self,typ_id):
# 获取count的值,即app总数
url = self.url.format(0,typ_id)
html = requests.get(
url=url,
headers={'User-Agent':UserAgent().random}
).json()
count = html['count']
pages = int(count) // 30 + 1
return pages
# url入队函数,拼接url,并将url加入队列
def url_in(self):
for id in self.id_list:
# id格式:('4',pages)
for page in range(1,id[1]+1):
url = self.url.format(page,id[0])
# 把URL地址入队列
self.q.put(url)
# 线程事件函数: get() -请求-解析-处理数据,三步骤
def get_data(self):
while True:
# 判断队列不为空则执行,否则终止
if not self.q.empty():
url = self.q.get()
headers = {'User-Agent':UserAgent().random}
html = requests.get(url=url,headers=headers)
res_html = html.content.decode(encoding='utf-8')
html=json.loads(res_html)
self.parse_html(html)
else:
break
# 解析函数
def parse_html(self,html):
# 写入到csv文件
app_list = []
for app in html['data']:
# app名称 + 分类 + 详情链接
name = app['displayName']
link = 'http://app.mi.com/details?id=' + app['packageName']
typ_name = app['level1CategoryName']
# 把每一条数据放到app_list中,并通过writerows()实现多行写入
app_list.append([name,typ_name,link])
print(name,typ_name)
self.i += 1
# 向CSV文件中写入数据
self.lock.acquire()
self.writer.writerows(app_list)
self.lock.release()
# 入口函数
def main(self):
# URL入队列
self.get_cateid()
t_list = []
# 创建多线程
for i in range(1):
t = Thread(target=self.get_data)
t_list.append(t)
# 启动线程
t.start()
for t in t_list:
# 回收线程
t.join()
self.f.close()
print('数量:',self.i)
if __name__ == '__main__':
start = time.time()
spider = XiaomiSpider()
spider.main()
end = time.time()
print('执行时间:%.1f' % (end-start))
25、bs4
pip install bs4
26、bs4爬取小说
import urllib.request
import random
from bs4 import BeautifulSoup
import time
def request_html(url):
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'}
request = urllib.request.Request(url, headers=headers)
return request
def parse_html(html, f):
# 生成soup对象
soup = BeautifulSoup(html, 'lxml')
# 查找所有的章节链接和标题内容
list_name = soup.select('.book-mulu > ul > li > a')
# 遍历每一个列表中的tag对象,获取链接个目录
for item in list_name:
# 获取链接
#item: <a href="/book/liangjinyanyi/1.html">自序</a>
#拼接目录链接,此处item类型为<class 'bs4.element.Tag'>,使用下面方法可以值获取href属性值
href = 'http://www.shicimingju.com' + item['href']
# 获取标题
title = item.text
print('正在下载:-**--%s--**-......' % title)
# 获取章节内容函数
text = get_text(href)
# 写入文件
f.write(title + '\n' + text)
print('结束下载:-**--%s--**-' % title)
time.sleep(random.uniform(0,1))
# 提取章节内容
def get_text(href):
#创建请求对象
request = request_html(href)
content = urllib.request.urlopen(request).read().decode('utf8')
soup = BeautifulSoup(content, 'lxml')
# 查找包含内容的tag--div
artist = soup.find('div', class_='chapter_content')
#获取tag标签中的文本内容
return artist.text
def run():
# 打开文件
f = open('两晋演义.txt', 'w', encoding='utf8')
url = 'http://www.shicimingju.com/book/liangjinyanyi.html'
# 构建请求对象
request = request_html(url)
# 发送请求,得到响应,转换为HTML对象
html = urllib.request.urlopen(request).read().decode('utf8')
# 解析内容
parse_html(html,f)
#关闭文件
f.close()
if __name__ == '__main__':
run()
浙公网安备 33010602011771号