爬虫基础

Python爬虫从入门到高级:
scrapy框架:

通用爬虫:百度,360,搜狐,谷歌,必应
原理:抓取网页,采集数据,数据处理,提供检索服务
聚焦爬虫:根据特定的需求,抓取指定的数据
思路:代替浏览器上网
网页的特点:1.都有自己的url,2. 网页内容都是url结构的,3.使用的都是http,https的协议
步骤:1、给一个url 2、写程序模拟浏览器访问url 3、解析内容,提取数据
robots.txt协议
用到的库:urllib/request/bs4…
(2)解析网络内容用到的知识:正则表达式,bs4,xpath,JsonPath
(3)涉及到动态html
selenium+phantomjs,chormheadless
(4)scrapy框架
高性能框架使用
(5)scrapy-redis组件
redis,分布式爬虫
(6)涉及到爬虫,反爬虫,反反爬虫的一些内容
UA,代理,验证码,动态页面

http(80)/https(443) ftp(21) ssh(22) 端口号
2.http协议:(https:比http协议多了个加密功能,多个SSL协议,比http协议安全)
服务端:公钥加密则私钥解密,私钥加密则公钥解密
加密:密钥 , 解密:密钥(对称加减密,加密和解密密钥一样,不一样则是非对称加解密)

什么是协议?双方规定的传输形式。
TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这种端点就叫做套接字(socket)或插口。
套接字用(IP地址:端口号)表示。
它是网络通信过程中端点的抽象表示,包含进行网络通信必需的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

http请求:get,post

get:则可以在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔,例如:GET/mall/1.html?name=abc&password=xyz HTTP/1.1
get 方式的特点:在URL地址后附带的参数是有限制的,其数据容量通常不能超过1K.
Post方式,则可以在请求的实体内容中向服务器发送数据,Post方式的特点:传送的数据量无限制。

3.fiddler
一个网页的呈现,中间不止一次http请求,平均一个网页得10-15此请求
谷歌:
右键开发者工具,network
右边栏:request headers response
(headers下面存在) query string : get 参数
(headers下面存在) from data : post 参数

fiddler:
2.抓包
<>:html内容
{json}:Json数据,很有可能是接口
{css}:css文件
{js}:js文件

停止抓取:file->capture 点击就会切换
点击请求,右边选中 Inspectors
右上:http请求信息
raw:请求头部的详细信息
webforms:请求所带参数,query_string formdata
右下:http响应信息
首先点击黄色条进行解码(Response body is encoded)
raw:响应的所有信息
headers:响应头
json: 接口返回的内容(ajax接口)

左下黑色框可以输入指令快捷操作
clear:清除所有请求
select json:快速选择所有json请求
select image:图片请求
select html:html请求
?内容:搜索包含这个内容的所有请求
敲enter执行
4.urllib库
模拟浏览器发送请求的库,Python自带
用到的库:urllib.request urllib.parse

字符串==》二进制字符串之间的转化
encode() 字符串=》字节类型
如果小括号里面不写参数,默认UTF-8(编码类型)
如果写,就写gbk(编码类型)
decode() 字节类型=》字符串
如果小括号里面不写参数,默认UTF-8
如果写,就写gbk
urllib.request
urlopen(url)
urlretrieve(url,image_path)

response
    response.read() #读取相应内容,内容是字节类型
    geturl()   获取请求的url
    getheaders()  获取头部信息,列表里面有元组
    getcode()  获取状态码
     readlines()  按行读取,返回列表

import urllib.request

url=“https://www.baidu.com”

#完整的url http://www.baidu.com/index.html?name=goudan&password=123#lala
#协议 域名 文件 参数 锚点

#response=urllib.request.urlopen(url=url)#发送请求,response为获取的响应

#print(response.read().decode()) #response.read()发送请求后给出的响应信息
#print(response.url)
#print(dict(response.getheaders())) #本身是元组的方式,转化到字典的方式

#print(response.getcode()) #获取网页源码
#print(response.readlines())

#with open(‘baidu.html’,‘w’,encoding=‘utf-8’) as fp: #写到文件中
#fp.write(response.read().decode()) #在文件中写入源代码

with open(‘baidu1.html’,‘wb’) as fp: #直接用字节的方式写到文件中,不用encoding和decode

fp.write(response.read())

#下载图片
image_url=‘https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1551238227&di=70dee5c0daec47b1205bd15ba3386d37&src=http://xnnews.com.cn/wenyu/lxsj/201709/W020170928754503027123.jpg’

#url只能由特定的字符组成,字母,数字,下划线
#如果出现其他的,比如 $ 空格 中文 等,就要对其进行编码
response=urllib.request.urlopen(image_url)

#像图片只能写入本地二进制的格式

with open(‘qing.jpg’,‘wb’) as fp:

fp.write(response.read())

urllib.request.urlretrieve(image_url,‘chun.jpg’)#直接将图片下载到文件中

urllib.parse
quote #url编码函数,将中文进行转化为%xxx
unquote #url解码函数,将%xxx转化为指定字符
urlencode #给一个字典,将字典拼接为query_string,并且实现了编码的功能。
import urllib.parse

url=‘http://www.baidu.com.index.html?name=goudan&age=18&sex=nv&height=180’

#假如参数有 name age sex height

name=‘狗蛋’
age=18
sex=‘女’
height=‘180’
data={
‘name’:name,
‘age’:age,
‘sex’:sex,
‘height’:height,
‘weight’:180,
}
#遍历字典

lt=[]

for k,v,in data.items():

lt.append(k+’=’+str(v))

query_string=’&’.join(lt)

query_string=urllib.parse.urlencode(data) #函数里面参数是字典,urlencode()函数就相当于遍历字典 #即使存在非法字符也可以直接编码

print(query_string)
url=url+’?’+query_string
print(url)

5.get请求:
输入文件名,就可以将文件名作为参数加在baidu.com/s?网址后面,进行百度查询
import urllib.request
import urllib.parse

word=input(‘请输入您想要搜索的能内容:’)

url=‘http://www.baidu.com/s?’
#参数写成字典
data={
‘ie’:‘utf-8’,
‘wd’: word,
}
query_string=urllib.parse.urlencode(data) #给一个字典,将字典拼接为query_string,并且实现了编码的功能。
url+=query_string

#发送请求
response=urllib.request.urlopen(url) #发送请求,response为获取的响应
filename=word+’.html’ #根据输入的word生成文件名
with open(filename,‘wb’) as fp: #生成文件
fp.write(response.read())

6.构建请求头部信息(这是反爬的第一步)
伪装自己的UA,让服务端认为你是浏览器在上网
构建请求对象:
urllib.request.Request():
实例:
import urllib.request
import urllib.parse

url=‘http://www.baidu.com/’

response=urllib.request.urlopen(url)

print(response.read().decode())

#自己要伪装的头部
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64)’
’ AppleWebKit/537.36 (KHTML, like Gecko)’
’ Chrome/72.0.3626.119 Safari/537.36’
}
#构建请求对象
request=urllib.request.Request(url=url,headers=headers)
#发送请求
response=urllib.request.urlopen(request)
print(response.read().decode()) #打印返回的源代码

DAY02-爬虫2
1.post
【注】表单数据的处理,
form_data=urllib.parse.urlencode(form_data).encode() #处理Post表单数据,处理后的数据必须是字节类型,调用encode()
在fiddler抓包中看到(一个本上面一个箭头)就是post请求

Post-1
import urllib.request
import urllib.parse

#获取Posturl的地址
post_url=‘https://fanyi.baidu.com/sug’
word=input(‘请输入你要查询的英文单词:’)
#构建post表单数据
form_data={
‘kw’:word,
}
#发送请求的过程
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64)’
‘AppleWebKit/537.36 (KHTML, like Gecko)’
‘Chrome/72.0.3626.119 Safari/537.36’
}
#构建请求对象

form_data=urllib.parse.urlencode(form_data).encode() #处理Post表单数据,处理后的数据必须是字节类型,调用encode()
request=urllib.request.Request(url=post_url,headers=headers)
#发送请求
response=urllib.request.urlopen(request,data=form_data)
print(response.read().decode())

Post-2
import urllib.request
import urllib.parse

post_url=‘https://fanyi.baidu.com/v2transapi’
formdata={
‘from’:‘en’,
‘to’:‘zh’,
‘query’:‘wolf’,
‘transtype’:‘enter’,
‘simple_means_flag’:‘3’,
‘sign’:‘275695.55262’,
‘token’:‘abbb564cc8f229fc66aaf97180bcb895’,
}
headers={
‘Host’: ‘fanyi.baidu.com’,
‘Connection’: ‘keep-alive’,
‘Content-Length’: ‘117’,
‘Accept’: ‘/’,
‘Origin’: ‘https://fanyi.baidu.com’,
‘X-Requested-With’: ‘XMLHttpRequest’,
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36’,
‘Content-Type’:‘application/x-www-form-urlencoded; charset=UTF-8’,
‘Referer’: ‘https://fanyi.baidu.com/?aldtype=16047’,
#‘Accept-Encoding’: ‘gzip, deflate, br’,
‘Accept-Language’: ‘zh-CN,zh;q=0.9’,
‘Cookie’: ‘BAIDUID=F38DB8ACED5567A19584C19CF8E240BF:FG=1; BIDUPSID=F38DB8ACED5567A19584C19CF8E240BF; PSTM=1551235384; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; delPer=0; H_PS_PSSID=1431_21115_18560_26350; PSINO=5; locale=zh; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1551259947; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1551259947; to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%2C%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D’,
}
request=urllib.request.Request(url=post_url,headers=headers)

formdata=urllib.parse.urlencode(formdata).encode()

response=urllib.request.urlopen(request,formdata)
print(response.read().decode())

2.ajax
get(发送请求前需要拼接url)实例:
import urllib.request
import urllib.parse

url=‘https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&’

#start=0 limit=20
page=int(input(‘请输入想要第几页的数据:’))
number=20

#构建get参数
data={
‘start’:(page-1)*number,
‘limit’:number,
}
#将字典转化为query_string
query_string=urllib.parse.urlencode(data)
#修改url
url+=query_string

headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64)’
‘AppleWebKit/537.36 (KHTML, like Gecko)’
‘Chrome/72.0.3626.119 Safari/537.36’
}
request=urllib.request.Request(url=url,headers=headers)
response=urllib.request.urlopen(request)
print(response.read().decode())
post(post请求在发送请求前需要把表单参数处理一下):
import urllib.request
import urllib.parse

post_url=‘http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname’
city=input(“请输入要查询的城市:”)
page=input(“请输入查询第几页:”)
size=input(“请输入要多少个:”)
form_data={
‘cname’: city,
‘pid’: ‘’,
‘pageIndex’: page,
‘pageSize’: size,
}
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64)’
’ AppleWebKit/537.36 (KHTML, like Gecko)’
’ Chrome/72.0.3626.119 Safari/537.36’
}
request=urllib.request.Request(url=post_url,headers=headers)
form_data=urllib.parse.urlencode(form_data).encode()
response=urllib.request.urlopen(request,form_data)
print(response.read().decode())

   复杂的get(爬取贴吧内容,输入名称,起始页,终结页,爬取信息放到文件夹中,以)
   import urllib.request

import urllib.parse
import os
url=‘http://tieba.baidu.com/f?ie=utf-8&’

#1 pn0
#2 pn
50
#3 pn=100 n pn==(n-1)*50
#输入吧名,输入起始页码,输入结束页码,然后在当前文件夹中创建一个以吧名为名字的文件夹,

里面是每一页的html内容,文件名是吧名_page.html

ba_name=input(‘请输入要爬取的吧名:’)
start_page=int(input(‘请输入要爬取的起始页码:’))
end_page=int(input(‘请输入要爬取的结束页码:’))

#创建文件夹
if not os.path.exists(ba_name):#如果文件夹命名不重复
os.makedirs(ba_name)
#搞个循环,依次爬取每一页数据
for page in range (start_page,end_page+1):
#page就是当前项
#拼接url过程
data={
‘kw’:ba_name,
‘pn’:(page-1)*50
}
data=urllib.parse.urlencode(data)
url_t=url+data #如果此处还是url话,就会在原有基础上加上data编译码
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64)’
‘AppleWebKit/537.36 (KHTML, like Gecko)’
‘Chrome/72.0.3626.119 Safari/537.36’
}
request=urllib.request.Request(url=url_t,headers=headers)
print(“第%s页开始下载。。。”%page)
response=urllib.request.urlopen(request)
filename=ba_name+’_’+str(page)+’.html’
#拼接文件路径
filepath=ba_name+’/’+filename
#写内容
with open(filepath,‘wb’) as fp:
fp.write(response.read())
print(“第%s页结束下载。。。” % page)

Post请求和Get请求(何时进行post请求,何时进行get请求):
https://www.jianshu.com/p/51eda5dbf8af

4、URLError\HTTPError
这两个类都在urllib.error中
NameError TypeError FileNotFound 异常
异常处理,结构 try-except
URLError:
(1)没有网
(2)服务器连接失败
(3)找不到指定的服务器

HttpError:
是URLError的子类
【注】两个同时捕获的时候,需要将HTTPError写到上面,URLError写到下面
5、Handler处理器,自定义Opener
urlopen() 给一个url,发送请求,获取响应
Request() 定制请求头,创建请求对象
高级功能:使用代理,cookie
基本用法:
import urllib.request
import urllib.parse

url=‘https://www.baidu.com/’
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64)’
’ AppleWebKit/537.36 (KHTML, like Gecko)’
’ Chrome/72.0.3626.119 Safari/537.36’
}
#创建一个handler
handler=urllib.request.HTTPHandler()
#通过handler创建一个opener
opener=urllib.request.build_opener(handler)#opener就是一个对象,一会发送请求的时候,

直接使用opener里面的方法即可,不要使用urlopen了

#构建请求对象
request=urllib.request.Request(url,headers=headers)
#发送请求
response=opener.open(request)
print(response.read().decode())

6、代理
代理是什么
程序中的代理
正向代理:客户端向服务器发送请求的代理(代理客户端获取数据)
反向代理:代替服务器获取接收的请求(代理服务端提供数据)

       配置:
               浏览器配置(软件:花刺代理验证)
                        右边三点,设置,高级,代理设置,局域网设置,为LAN使用代理,输入ip和端口号即可
               代码配置

#创建handler
handler=urllib.request.ProxyHandler({‘http’:‘114.215.95.188:3128’})#代理ProxyHandler
#常见opener
opener=urllib.request.build_opener(handler)
后续都使用openner.open方法发送请求即可

import urllib.request
import urllib.parse

#创建handler
handler=urllib.request.ProxyHandler({‘http’:‘114.215.95.188:3128’})#代理ProxyHandler
#常见opener
opener=urllib.request.build_opener(handler)

url=‘https://www.baidu.com/s?ie=UTF-8&wd=ip’
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64)’
’ AppleWebKit/537.36 (KHTML, like Gecko)’
’ Chrome/72.0.3626.119 Safari/537.36’
}
request=urllib.request.Request(url,headers=headers)
response=opener.open(request)
with open(‘ip.html’,‘wb’) as fp:
fp.write(response.read())

7、cookie
cookie:登录的时候服务端给你留下的身份信息
http协议:无状态
网站登录的时候的问题,用来记录用户身份的
模拟登录
抓包获取cookie,发送请求


day03-爬虫3
1、cookie登录
import urllib.request
import urllib.parse
import http.cookiejar

#真实的模拟浏览器,当发送完post请求的时候,将cookie保存到代码中
#创建一个cookiejar对象
cj=http.cookiejar.CookieJar() #cookie就保存到这里面
#通过cookiejar创建一个handler
handler=urllib.request.HTTPCookieProcessor(cj)
#根据handler创建一个opener
opener=urllib.request.build_opener(handler)
#再往下所有发送请求的操作都是用opener操作,因为这里面带着cookie过去了

post_url='http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2019201456741 ’

formdata={
‘email’:‘13551324861’,
‘icode’: ‘’,
‘origURL’:‘http://www.renren.com/home’,
‘domain’:‘renren.com’,
‘key_id’:‘1’,
‘captcha_type’:‘web_login’,
‘password’:‘3b5a3c0fcddf621b5acf8e0824154e8bdd355638e4a216d23efa7994a74aeb91’,
‘rkey’:‘fc34cdc91614eb255a642b5d0480480d’,
‘f’:‘https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DLsZYtgqx5HXR9PIWt3wgccbPq9lOdR77u0oqL0zzMk3%26wd%3D%26eqid%3Dca19ff740008a6f1000000045c7b7a17’,
}
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) ’
‘AppleWebKit/537.36 (KHTML, like Gecko)’
’ Chrome/72.0.3626.119 Safari/537.36’

}
request=urllib.request.Request(url=post_url,headers=headers)
formdata=urllib.parse.urlencode(formdata).encode()
#response=urllib.request.urlopen(request,data=formdata)
response=opener.open(request,data=formdata)

print(response.read().decode())
print(’*’*50)
get_url=‘http://www.renren.com/969916588/profile’
request=urllib.request.Request(url=get_url,headers=headers)
#response=urllib.request.urlopen(request)
response=opener.open(request)
print(response.read().decode())

2、正则表达式解析
匹配一类具有相同规则的字符串
re.compile() 函数
编译正则表达式模式,返回一个对象。可以把常用的正则表达式编译成正则表达式对象,方便后续调用及提高效率。
规则:
单字符:. [] \d \D \w \W \s \S
. : 除换行以外所有字符
[ ] :[aoe]a或e [ a-w] a到w 之间任意一个
\d:数字 【0-9】
\D: 非数字
\w: 数字,字母,下划线,中文
\W:非\w
\s:所有的空白字符
\S:非空白字符
数量修饰:
* :任意多次 >=0
+ :至少一次 >=1
?:可有可无 0或1次
{m}:固定m次
{m,}:至少m次
{m,n}:m-n次
边界:
\b
\B
$ :以某某结尾
^ :以某某开头
分组:
ab{3}:限制b出现三次
(){4}:视为一个整体
() : 子模式\组模式 \1 \2
子模式:
import re
string=‘

猪八戒


#pattern=re.compile(r’<(\w+)><(\w+)>\w+’)#去掉r 没啥意义
pattern=re.compile(’<(\w+)><(\w+)>\w+’)
ret=pattern.search(string)
print(ret)

贪婪模式:
.*? .+?
re.I :忽略大小写
re.M:多行匹配
re.S:单行匹配
match:从头开始找\search从任意位置开始找\找所有
正则替换:
例1:
import re
string=‘i love you,you love me,ye’
pattern=re.compile(r’love’)
#ret1=re.sub(pattern,‘hate’,string)
ret2=re.sub(r’love’,‘hate’,string)#三种都可以
#ret=pattern.sub(‘hate’,string)
print(ret2)
例2:
def fn(a):
ret=int(a.group())# a只是一个正则匹配到的对象,要将正则匹配到的内容拿出来用group()
return str(ret-10)
string=‘我喜欢身高为175的女孩’
pattern=re.compile(r’\d+’)
ret=pattern.sub(fn,string)
print(ret)
re.sub(正则表达式,替换内容,字符串) #在字符串中找到正则表达式内容替换为替换内容
import re
#string=‘

猪八戒


string=’’‘hate is asdasdh feel
love you asda
love asdfsdf
love fffff
‘’’
string1=’’'
沁园春-雪
北国风光
千里冰封
万里雪飘
望长城内外
惟余莽莽
大河上下
顿失滔滔
山舞银蛇
原驰蜡象
''' #pattern=re.compile(r'<(\w+)><(\w+)>\w+

#pattern=re.compile(r’^love’,re.M)
#ret=pattern.search(string)
pattern=re.compile(r’

(. ?)
’,re.S)#如果只想要文字,就只能是(.?)[贪婪模式],如果还想要后面的就<.*>
ret=pattern.findall(string1)
print(ret)

输出:[‘沁园春-雪\n北国风光\n千里冰封\n万里雪飘\n望长城内外\n惟余莽莽\n大河上下\n顿失滔滔\n山舞银蛇\n原驰蜡象\n’]
http://www.yikexun.cn/

爬取糗图图片:
代码:
import urllib.request
import urllib.parse
import re
import os
import time
url=‘https://www.qiushibaike.com/pic/page/2/’

def handle_request(url,page):
url=url+str(page)+’/’
#print(url)
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) ’
‘AppleWebKit/537.36 (KHTML, like Gecko)’
’ Chrome/72.0.3626.119 Safari/537.36’
}
request=urllib.request.Request(url,headers=headers)
return request

def download_image(content): #把页面代码中 pattern=re.compile(r’

. ??>.?
’,re.S)#正则(.*?)代替想要拿去的内容
lt=pattern.findall(content)
print(lt)
#遍历列表,依次下载图片
for image_src in lt:
image_src=‘https:’+image_src
#创建文件夹
dirname=‘qiutu’
if not os.path.exists(dirname):
os.makedirs(dirname)
#图片的名字叫啥
filename=image_src.split(’/’)[-1]
filepath=dirname+’/’+filename
print("%s图片正在下载。。。。" %filename)
#发送请求,下载图片
urllib.request.urlretrieve(image_src,filepath)
print("%s图片结束下载。。。。" % filename)
time.sleep(1)
def main():
url = ‘https://www.qiushibaike.com/pic/page/’
start_page=int(input(‘请输入起始页码:’))
end_page=int(input(‘请输入结束页码:’))
for page in range(start_page,end_page+1):
print(‘第%s页开始下载。。。。’%page)
#生成请求对象
request=handle_request(url,page)#根据不同的页码生成的url进行的发送请求
#发送请求对象,获取响应内容
content=urllib.request.urlopen(request).read().decode()
#解析内容,提取所有的图片链接下载图片
download_image(content)
print()
time.sleep(2)

if name==‘main’:
main()
需求:
爬取指定页面的标题和内容
保存到html文件中,标题用h1,内容使用p即可

爬取励志网的内容,包括子页面内容的全部信息:
代码:
import urllib.request
import urllib.parse
import re

def handle_request(url,page=None):
#拼接出指定的url
if page!=None:#此处这种写法是为了get_text()函数方法能够直接调用此处函数
url=url+str(page)+’.html’
headers={
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) ’
‘AppleWebKit/537.36 (KHTML, like Gecko)’
’ Chrome/72.0.3626.119 Safari/537.36’,
}
request=urllib.request.Request(url=url,headers=headers)
return request
def get_text(a_href):
#调用函数,构建请求对象:
request=handle_request(a_href)
#发送请求,获得响应
content=urllib.request.urlopen(request).read().decode()
#解析内容
pattern=re.compile(r’

(. ?)
’,re.S)
lt=pattern.findall(content)
text=lt[0]
#写个正则,将内容中的所有图片全部清空
pat=re.compile(r’’)
text=pat.sub(’’,text) #将text正则中所有图片的正则替换成空,相当于删除图片链接
return text

def parse_content(content):
#写正则
pattern=re.compile(r’

(.*?)

’)#正则中想获取哪个位置的内容就在哪里加()
#返回的lt是一个列表,列表中的元素都是元组,元组中的第一个元素就是正则中第一个小括号匹配到的内容,
# 元组中第二个元素就是正则中第二个小括号匹配到的内容
lt=pattern.findall(content)
#遍历列表
for href_title in lt:
a_href=‘http://www.yikexun.cn’+href_title[0]#获取内容的链接
title=href_title[-1]#获取标题
#向a_href发送请求,获取响应内容,就是具体的故事信息
text=get_text(a_href)
#写到html文件中
string=’

%s

%s’%(title,text)
#with open(‘lizhi.html’,‘ab’) as fp:
#fp.write(string.encode())
with open(‘lizhi.html’,‘a’,encoding=‘utf-8’) as fp:
fp.write(string)

def main():
url=‘http://www.yikexun.cn/lizhi/qianming/list_50_’
start_page=int(input(‘请输入起始页码:’))
end_page=int(input(‘请输入结束页码:’))
for page in range(start_page,end_page+1):
#根据url和page生成指定的request
request=handle_request(url,page)
content=urllib.request.urlopen(request).read().decode()
#解析内容
parse_content(content)

if name==‘main’:
main()

3、bs4
BeautifulSoup
需要将pip源设置为国内源
windows:打开“此电脑”,地址栏上输入%appdata%,新建一个pip文件夹,里面新建一个pip.ini文件(文本文件改后缀名),里面输入
[global]
timeout=6000
index-url=https://mirrors.aliyun.com/pypi/simple
trusted-host=mirrors.aliyun.com
linux:(1)cd~
(2)mkdir ~/.pip
(3)vi ~/.pip/pip.conf
(4)编辑内容,和windows一模一样
需要安装:pip install bs4(在你选择存放文件的文件夹中长按shift键,右击空白处,点击在此处打开powershell窗口,输入pip install bs4)
bs4需要一个第三方的库,安装库
pip install lxml
简单使用:
说明:选择器,jquery
from bs4 import BeautifulSoup
使用方式:可以将一个html文档转化成指定对象,然后通过对象的方法或属性查找指定的内容
(1)转化为本地文件:
soup=BeautifulSoup(open(‘本地文件’),‘lxml’)
(2)转化为网络文件:
soup=BeautifulSoup(‘字符串类型或者字节类型’,‘lxml’)#lxml是解析器
(1) 根据标签名查找
soup.a#只能找到第一个符合要求的标签
(2)获取属性
soup.a.attrs 获取所有的属性和值,返回一个字典
例:{‘href’: ‘http://www.song.com’, ‘title’: ‘赵匡胤’, ‘target’: ‘_self’}
soup.a.attrs[‘href’] 获取href属性 http://www.song.com
soup.a[‘href’] 也可简写为这种形式
(3)获取内容
print(soup.a.string) #返回的只能是文本,如果标签里面还存在标签,只返回None,比较脆弱
print(soup.a.text) 而其他两个可以获取文本内容
print(soup.a.get_text())
例:宋超爱四大皆空康达科技部
print(soup.div.text)
print(soup.div.string)
print(soup.div.get_text())
输出: 甄姬
百里守约
李白
太乙真人

None

    甄姬
    百里守约

李白
太乙真人
(4)find
soup.find(‘a’) 找到第一个符号要求的a
print(soup.find(‘a’,title=‘qing’)) 根据a和title查找
print(soup.find(‘a’,alt=‘mei’)) 根据a和title查找
print(soup.find(‘a’,id=‘123’)) 根据a和123查找
print(soup.find(‘a’,class_=‘a’)) #此处因为class关键字,所有不能直接用class,加个下划线
div=soup.find(‘div’,class_=“song”)#先找到符合条件的div
print(div.find(‘a’,class_=“a”))#再从div中找到符合条件的a

find方法不仅soup可以调用,普通的div对象也能调用,会去指定的div里面去查找符合要求的节点
find找到的都是第一个符合要求的标签
(5) find_all
soup.find_all(‘a’) 找到所有a
soup.find_all([‘a’,‘b’]) 找到所有a,b
soup.find_all(‘a’,limit=2) 限制前两个
(6)select
在 CSS 中,选择器是一种模式,用于选择需要添加样式的元素。
根据选择器选择指定的内容
常见的选择器:标签选择器,类选择器,id选择器,组合选择器,层级选择器,伪类选择器,属性选择器(参照css选择器参开手册)
a
.dudu
#lala
a, .dudu, #lala, .meme
div .dudu #lala .meme .xixi 下面好多级
div > p > a> .lala 只能是下面一级*(>前面加空格)
input[name=‘lala’]
选择器 例子 例子描述 CSS
.class .intro 选择 class=“intro” 的所有元素。 1
#id #firstname 选择 id=“firstname” 的所有元素。 1

    • 选择所有元素。 2
      element p 选择所有

      元素。 1
      element,element div,p 选择所有

      元素和所有

      元素。 1
      element element div p 选择

      元素内部的所有

      元素。 1
      element>element div>p 选择父元素为

      元素的所有

      元素。 2
      element+element div+p 选择紧接在

      元素之后的所有

      元素。 2
      [attribute] [target] 选择带有 target 属性所有元素。 2
      [attribute=value] [target=_blank] 选择 target="_blank" 的所有元素。 2
      [attribute~=value] [title~=flower] 选择 title 属性包含单词 “flower” 的所有元素。 2
      [attribute|=value] [lang|=en] 选择 lang 属性值以 “en” 开头的所有元素。 2
      :link a:link 选择所有未被访问的链接。 1
      :visited a:visited 选择所有已被访问的链接。 1
      :active a:active 选择活动链接。 1
      :hover a:hover 选择鼠标指针位于其上的链接。 1
      :focus input:focus 选择获得焦点的 input 元素。 2
      :first-letter p:first-letter 选择每个

      元素的首字母。 1
      :first-line p:first-line 选择每个

      元素的首行。 1
      :first-child p:first-child 选择属于父元素的第一个子元素的每个

      元素。 2
      :before p:before 在每个

      元素的内容之前插入内容。 2
      :after p:after 在每个

      元素的内容之后插入内容。 2
      :lang(language) p:lang(it) 选择带有以 “it” 开头的 lang 属性值的每个

      元素。 2
      element1~element2 p~ul 选择前面有

      元素的每个

        元素。 3
        [attribute^=value] a[src^=“https”] 选择其 src 属性值以 “https” 开头的每个 元素。 3
        [attribute = v a l u e ] a [ s r c =value] a[src =value]a[src=".pdf"] 选择其 src 属性以 “.pdf” 结尾的所有 元素。 3
        [attribute*=value] a[src*=“abc”] 选择其 src 属性中包含 “abc” 子串的每个 元素。 3
        :first-of-type p:first-of-type 选择属于其父元素的首个

        元素的每个

        元素。 3
        :last-of-type p:last-of-type 选择属于其父元素的最后

        元素的每个

        元素。 3
        :only-of-type p:only-of-type 选择属于其父元素唯一的

        元素的每个

        元素。 3
        :only-child p:only-child 选择属于其父元素的唯一子元素的每个

        元素。 3
        :nth-child(n) p:nth-child(2) 选择属于其父元素的第二个子元素的每个

        元素。 3
        :nth-last-child(n) p:nth-last-child(2) 同上,从最后一个子元素开始计数。 3
        :nth-of-type(n) p:nth-of-type(2) 选择属于其父元素第二个

        元素的每个

        元素。 3
        :nth-last-of-type(n) p:nth-last-of-type(2) 同上,但是从最后一个子元素开始计数。 3
        :last-child p:last-child 选择属于其父元素最后一个子元素每个

        元素。 3
        :root :root 选择文档的根元素。 3
        :empty p:empty 选择没有子元素的每个

        元素(包括文本节点)。 3
        :target #news:target 选择当前活动的 #news 元素。 3
        :enabled input:enabled 选择每个启用的 元素。 3
        :disabled input:disabled 选择每个禁用的 元素 3
        :checked input:checked 选择每个被选中的 元素。 3
        :not(selector) :not§ 选择非

        元素的每个元素。 3
        ::selection ::selection 选择被用户选取的元素部分。 3

例:
soup=BeautifulSoup(open(‘soup_text.html’,encoding=‘utf8’),‘lxml’)
div=soup.find(‘div’,class_=“tang”)
print(soup.select(’.tang > ul > li > a’)[2])#>前面加空格
print(soup.select(’#feng’)) #选择器选出来的都是列表
print(soup.select(’#feng’)[0].text) #获取内容
print(soup.select("#feng")[0][‘href’])#获取href属性

print(div.select(’.a’))
select选择器返回的是列表,需要通过下标提取指定的对象,然后获取属性和结点,该方法也可以通过普通对象调用,找到的都是这个对象下面符合要求的所有节点

DAY-4
import json
把信息存储到字典中,
for table in table_list:
zwmc=table.select(’.zwmc>div>a’)[0].text
gsmc=table.select(’.gsmc>a’)[0].text
zwyx=table.select(’.zwmc’)[0].text
gzdd=table.select(’.gzdd’)[0].text
gxsj=table.select(’.gxsj>span’)[0].text
item={
‘职位信息’:zwmc,
’ ':gsmc,
’ ':zwyx,
’ ':gzdd,
’ ':gxsj,
}
#再放到列表中
self.items.append(item)

string=json.dumps(self.items,ensure_ascii=False) #将字典转化为json,加上ensure_ascii=False就可以使获取的json格式转为文字
#保存到文件中
with open(’‘zhilian.txt’,‘w’,encoding=‘utf-8’) as fp:
fp.write(string)

2.xpath

http://www.w3school.com.cn/xpath/xpath_syntax.asp
pip install lxml
什么是xpath?
xml是用来存储和传输数据使用的
和html的不同:
(1)html用来显示数据,xml是用来传输数据
(2)html标签固定,xml标签自定义的
xpath用来在xml中查找指定的元素,它是一种路径表达式

常用的路径表达式:
// :不考虑位置的查找
./ :从当前节点开始往下查找
…/:从当前节点的父节点查找
@:选取属性
/bookstore/book选取属于bookstore的子元素的所有的直接子节点book元素
//book选取所有book子元素
bookstore//book查找bookstore下面所有book元素
//@lang 选取名为lang的所有节点
/bookstore/book[1] bookstore里面的第一个book
/bookstore/book[last()] bookstore里面的最后一个book
/bookstore/book[position()❤️] bookstore里面前两个book
//title[@lang] 所以的带有lang属性的title
//title[@lang=‘eng’] 所以得lang属性值为eng的title节点

  • 任何元素节点(通配符)
    安装XPATH插件
    将xpath插件拖动到谷歌浏览器扩展程序中,安装启动和关闭插件
    ctrl+shift+x
    属性定位
    //input[@id=“kw”]
    //input[@class=“bg s_btn”]

层级定位:
索引定位:
//div[@id=“head”]/div/div[2]/a[@class=“toindex”] 【注】索引从1开始
result:百度首页
//div[@id=“head”]//a[@class=“toindex”] 【注】双斜杠代表下面所有的a节点,不管位置

逻辑运算:
//input[@class=“s_ipt” and @name=“wd”]

模糊匹配:
contains:
//input[contains(@class,“s_i”)] 所有input有class属性且属性中带有s_i的节点
starts-with:
//input[starts-with(@class,“s”)] 所有的input,有class属性,并且属性以s开头
//li[contains(text(),“爱”)/text()]
取文本:
//div[@id=“u1”]/a[5]/text() 获取节点内容
//div[@id=“u1”]//text() 获取节点里面不带标签的所以内容

取属性:
//div[@id=“u1”]/a[5]/@href

代码中使用:
from lxml import etree/*-/
两种方式使用:将html文档变成一个对象,然后调用对象的方法查找指定节点
(1)本地文件
tree=etree.parse(文件名)
(2)网络文件
tree=etree.HTML(网页字符串)
ret=tree.xpath(‘路径表达式’) #ret是一个列表

#直接就把获得内容拼接起来给你
ret =tree.xpath(’//div[@class=“song”]’)# 找到div下面所有文字
string =ret[0].xpath(‘string(.)’) #对象拿出来,用这个函数就可以把获取的对象连起来,可以当字符串使用
print(string.replace(’\n’,’ ‘).replace(’\t’,’ '))

#from lxml import etree 此处导入etree的时候出现导入不进去的情况,etree下面存在红线,但是也可以用

import lxml.html 可用下面两句话代替
etree=lxml.html.etree

实例:
from lxml import etree
import urllib.request
import urllib.parse
import time
import json

import lxml.html

etree=lxml.html.etree

item_list=[]
def handle_request(url,page):
headers={
‘User - Agent’: ‘Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 72.0 .3626.121Safari / 537.36’

}
#url=url%page  #拼接url,将url和page进行拼接
url=url.format(page)
request=urllib.request.Request(url,headers=headers)
return request

def parse_content(content):
#生成对象
tree=etree.HTML(content)
#抓取内容
div_list=tree.xpath(’//div[@class=“log cate6 auth1”]’)
#遍历div列表
for odiv in div_list:
#获取标题
title=odiv.xpath(’.//h3/a/text()’)[0] #就一个内容也要取 ,注意加个点,在odiv中获取
text_lt=odiv.xpath(’.//div[@class=“cont”]/p/text()’) #得到的是一个列表
text=’\n’.join(text_lt) #\n是用来加换行
item ={
‘标题’:title,
‘内容’:text,
}
#将内容添加到列表中
item_list.append(item)

def main():
start_page=int(input(‘请输入起始页码:’))
end_page=int(input(‘请输入结束页码:’))
url=‘http://www.haoduanzi.com/category-10_{}.html’
for page in range(int(start_page),int(end_page)+1):
request=handle_request(url,page)
content=urllib.request.urlopen(request).read().decode()
#解析内容
parse_content(content)
time.sleep(2)
string=json.dumps(item_list,ensure_ascii=False) #如果你要处理的是文件而不是字符串,你可以使用 json.dump() 和 json.load() 来编码和解码JSON数据。
with open(‘duanzi.txt’,‘w’,encoding=‘utf8’) as fp:
fp.write(string)
if name==‘main’:
if name == ‘main’:
main()

你可能感兴趣的:(爬虫基础)