爬虫基础

中秋三天,把爬虫一些基础的东西过了一遍,还没有过完,等以后有时间了再来继续
Day1******************************************************************

1、网络爬虫

1、定义 :网络蜘蛛、网络机器人,抓取网络数据的程序
2、总结 :用Python程序去模仿人去访问网站,模仿的越逼真越好
3、爬取数据的目的 :通过有效的大量数据分析市场走势、公司决策

2、企业获取数据的方式

1、公司自有数据
2、第三方数据平台购买
数据堂、贵阳大数据交易所
3、爬虫爬取数据
市场上没有或者价格太高,利用爬虫程序爬取

3、Python做爬虫优势

请求模块、解析模块丰富成熟,强大的scrapy框架
PHP :对多线程、异步支持不太好
JAVA :代码笨重,代码量很大
C/C++ :虽然效率高,但是代码成型很慢

4、爬虫分类

1、通用网络爬虫(搜索引擎引用,需要遵守robots协议)

http://www.taobao.com/robots.txt
1、搜索引擎如何获取一个新网站的URL
  1、网站主动向搜索引擎提供(百度站长平台)
  2、和DNS服务网(万网),快速收录新网站

2、聚焦网络爬虫

自己写的爬虫程序:面向主题的爬虫、面向需求的爬虫

5、爬取数据步骤:

1)、确定需要爬取的URL地址

2)、通过HTTP/HTTPS协议来获取相应的HTML页面

3)、提取HTML页面有用的数据

    1、所需数据,保存
    2、页面中有其他的URL,继续 第2步

6、Anaconda和Spyder

1)、Anaconda :开源的Python发行版本

2)、Spyder :集成开发环境

Spyder常用快捷键:
  1、注释/取消注释 :ctrl + 1(数字)
  2、保存 :ctrl + s
  3、运行程序 :f5
  4、自动补全 :Tab

7、Chrome浏览器插件

1)、安装步骤

1、右上角 - 更多工具 - 扩展程序
2、点开右上角 - 开发者模式
3、把插件 拖拽到 浏览器页面,释放鼠标,点击 添加扩展...

2、插件介绍

1、Proxy SwitchOmega :代理切换插件
2、Xpath Helper :网页数据解析插件
3、JSON View    :查看json格式的数据(好看)

8、Fiddler抓包工具

添加证书信任的方法:证书生成器(fiddlercertmaker.exe)

1)、抓包工具设置

1、Tools->options->HTTPS->...from browers only
2、connections :设置端口号 8888

2)、设置浏览器代理

Proxy SwitchOmega -> 选项 -> 新建情景模式 -> HTTP 127.0.0.1 8888 -> 应用选项

浏览器右上角图标 -> AID1806 -> 访问百度

9、WEB

1)、HTTP和HTTS

1、HTTP :80
2、HTTPS :443,HTTP的升级版,加了一个安全套接层(socket)

2)、GET和POST

1、GET :查询参数都会在URL上显示出来
2、POST:查询参数和需要提交数据是隐藏在Form表单里的,不会在URL地址上显示

3)、URL :统一资源定位符

https://  item.jd.com  :80   /26809408972.html #detail
 协议     域名/IP地址  端口  访问资源的路径    锚点(data-anchor:写哪跳到哪)

4)、User-Agent

记录用户的浏览器、操作系统等,为了让用户获取更好的HTML页面效果
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
我的电脑:
`User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36`
User-Agent大全
Mozilla Firefox :(Gecko内核)
IE :Trident(自己的内核)
Linux : KTHML(like Gecko)
Apple :Webkit(like KHTML)
Google:Chrome(like Webkit)
其他浏览器都是模仿IE/Chrome

10、爬虫请求模块:发请求-响应——解析

1)、版本

1、python2 :urllib2、urllib
2、python3 :把urllib和urllib2合并,urllib.request

2)、常用方法

1、urllib.request.urlopen("网址")
例子:
import urllib.request

# response为响应对象
response = urllib.request.urlopen("http://www.baidu.com/")
html = response.read().decode("utf-8")

print(html)

  1、作用 :向网站发起一个请求并获取响应
    字节流 = response.read()
    字符串 = response.read().decode("utf-8")

    #encode()  字符串 --> bytes数据类型
	#decode()  bytes数据类型 --> 字符串

  2、重构User-Agent
    1、不支持重构User-Agent :urlopen()
    2、支持重构User-Agent
      urllib.request.Request(添加User-Agent)
2、urllib.request.Request("网址",headers="字典")
  User-Agent是爬虫和反爬虫斗争的第一步,发送请求必须带User-Agent
  1、使用流程
    1、利用Request()方法构建请求对象
	2、利用urlopen()方法获取响应对象
	3、利用响应对象的read().decode("utf-8")获取内容
	例子:
		url = "https://www.baidu.com/"
		headers = {"User-Agent":"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"}
		import urllib.request
		#1.创建一个请求对象(User-Agent)
		req = urllib.request.Request(url,headers = headers)
		#2.获取响应对象(urlopen())
		res = urllib.request.urlopen(req)
		#3.响应对象read().decode("utf-8")
		html = res.read().decode("utf-8")
		print(html)
  2、响应对象response的方法
    1、read() :读取服务器响应的内容
	2、getcode()作用:返回HTTP的响应码
		  print(respones.getcode())
		  200 :成功
		  4XX :服务器页面出错
		  5XX :服务器出错
	3、geturl()作用 :返回实际数据的URL(防止重定向问题)
	例子:
	import urllib.request
	url = "http://www.baidu.com/"
	headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"}
	# 1.创建请求对象(有User-Agent)
	req = urllib.request.Request(url,headers=headers)
	# 2.获取响应对象(urlopen())
	res = urllib.request.urlopen(req)
	# 3.响应对象read().decode("utf-8")
	#html = res.read().decode("utf-8")
	#print(html)
	print(res.getcode())
	print(res.geturl())
3、urllib.parse模块
secret:%E8%B0%A2%E7%A6%B9%E6%95%8F
	1、urlencode(字典)  ## 注意:参数一定要为字典
	   urlencode({"wd":"美女"})
	   wd=%e8.......
	   tedu = {"wd":"万科"}
	   示例见 :04_urllib.parse.urlencode示例.py
	   #%E8%B0%A2%E7%A6%B9%E6%95%8F
		import urllib.parse
		tedu = {"miss":"miss you"}
		tedu = urllib.parse.urlencode(tedu)
		print(tedu)

	 请输入你要搜索的内容:美女
	 保存到本地文件 :美女.html
	 代码:
		import urllib.request
		import urllib.parse
		#拼接URL
		baseurl = "http://www.baidu.com/s?"
		key = input("请输入要搜索的内容:")
		#进行URLencode()编码
		wd = {"wd":key}
		key = urllib.parse.urlencode(wd)
		url = baseurl + key
		headers = {"User_Agebt":"MOzilla/5.0"}
		#创建请求对象
		req = urllib.request.Request(url,headers = headers)
		#获取响应对象
		res = urllib.request.urlopen(req)
		html = res.read().decode("utf-8")
		#写入本地文件
		with open("搜索.html","w",encoding = "gb18030") as f:
			f.write(html)

	2、quote(字符串) 
	  key = urllib.parse.quote("字符串")
	  baseurl = "http://www.baidu.com/s?wd="
	  key = input("请输入要搜索的内容:")
	  #进行quote()编码
	  key = urllib.parse.quote(key)
	  url = baseurl + key
	  print(url)
	  例子:
		import urllib.request
		import urllib.parse
		#拼接URL
		baseurl = "http://www.baidu.com/s?wd="
		key = input("请输入要搜索的内容:")
		#进行quote()编码

		key = urllib.parse.quote(key)
		url = baseurl + key
		print(url)
		headers = {"User_Agebt":"MOzilla/5.0"}
		#创建请求对象
		req = urllib.request.Request(url,headers = headers)
		#获取响应对象
		res = urllib.request.urlopen(req)
		html = res.read().decode("utf-8")
		#写入本地文件
		with open("搜索2.html","w",encoding = "gb18030") as f:
			f.write(html)

4、练习

百度贴吧数据抓取
要求:
  1、输入要抓取的贴吧名称
  2、输入爬取的起始页和终止页
  3、把每一页的内容保存到本地
    第1页.html 第2页.html ... ... 
步骤:
  1、找URL规律,拼接URL
    第1页:http://tieba.baidu.com/f?kw=??&pn=0
	第2页:http://tieba.baidu.com/f?kw=??&pn=50
	第3页:http://tieba.baidu.com/f?kw=??&pn=100
.....
	第n页:pn=(n-1)*50

  2、获取网页内容(发请求获响应)
  3、保存(本地文件、数据库)
  例子:易烊千玺百度贴吧抓取
import urllib.request
import urllib.parse
import random
import time
#随机获取一个User-Agent
header_list = [{"User-Agent":"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"},
				 {"User-Agent":"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"},
				 {"User-Agent":"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"}]
 
headers = random.choice(header_list)
#主体程序
name = input("请输入贴吧名:")
begin = int(input("请输入起始页:"))
end = int(input("请输入终止页:"))
#对贴吧名name进行编码
kw = {"kw":name}
kw = urllib.parse.urlencode(kw)
#拼接url,发请求,获响应
for i in range(begin,end + 1):
	#拼接url
	pn = (i -1) * 50
	url = "http://tieba.baidu.com/f?" + kw + "&pn=" + str(pn)
	#http://tieba.baidu.com/f?kw=??&pn=0
	#发请求
	req = urllib.request.Request(url,headers = headers)
	res = urllib.request.urlopen(req,timeout = 5)
	time.sleep(2)
	html = res.read().decode("utf-8")
	#写入文件
	filename = "第" + str(i) + "页.html"
	with open(filename,"w",encoding="utf-8") as f:
		print("正在爬取第%d页" % i)
		f.write(html)
		print("第%d页爬取成功" % i)
		print("*" * 30)

11、请求方式及实例

1)、GET

1、特点 :查询参数在URL地址中显示
2、案例 :抓取百度贴吧

2)、POST(在Request方法中添加data参数)

1、urllib.request.Request(url,data=data,headers=headers)
data :表单数据以bytes类型提交,不能是str
2、处理表单数据为bytes类型
  1、把Form表单数据定义为字典data
  2、urlencode(data)
  3、转为bytes数据类型 :bytes()
3、有道翻译案例
代码:
import urllib.request
import urllib.parse
#请输入你要翻译的内容
key = input("请输入要翻译的内容:")
#把提交的form表单数据转为bytes数据类型
data = {"i": key,
		"from": "AUTO",
		"to": "AUTO",
		"smartresult": "dict",
		"client": "fanyideskweb",
		"salt": "15683634125285",
		"sign": "44c86c0701f282f0c07bc8020847b2a6",
		"ts": "1568363412528",
		"bv": "53539dde41bde18f4a71bb075fcf2e66",
		"doctype": "json",
		"version": "2.1",
		"keyfrom": "fanyi.web",
		"action": "FY_BY_REALTlME",
		"typoResult":"false"
		}
#字符串 i = python& from =auto...
data = urllib.parse.urlencode(data)
data = bytes(data,"utf-8")
#发请求,获取响应
#url为POST的地址,抓包工具抓到的,此处去掉_o
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"
headers = {"User-Agent":"Mozilla/5.0"}
#此处data为form表单数据,为bytes数据类型
req = urllib.request.Request(url,data = data,headers = headers)
res = urllib.request.urlopen(req)
html = res.read().decode("utf-8")
print(html)
4、有道翻译返回的是json格式的字符串,如何把json格式的字符串转换为Python中字典
  import json

  r_dict = json.loads(r_json)

day2*******************************************************************************

1、解析

1、数据的分类

1、结构化数据
  特点 :有固定的格式,如 :HTML、XML、JSON
2、非结构化数据
  示例 :图片、音频、视频,这类数据一般都存储为二进制

2、正则表达式re

1、使用流程
  1、创建编译对象 :p = re.compile("正则表达式")
  2、对字符串匹配 :r = p.match("字符串")
  3、获取匹配结果 :print(r.group())
2、常用方法
  1、match(s) :字符串开头的第1个,返回对象
  2、search(s):从开始往后找,匹配第1个,返回对象
  3、group()  :从match或search返回对象中取值
  4、findall():所有全部匹配,返回一个列表
3、表达式
  .  匹配任意字符(不能匹配\n)
  \d 数字
  \s 空白字符
  \S 非空白字符  
  [...] 包含[]内容 :A[BCD]E  --> ABE  ACE  ADE 
  \w 字母、数字、_

  *  前一个字符出现0次或多次
  ?  前一个字符出现0次或1次
  +  前一个字符出现1次或多次
  {m} 前一个字符出现m次
  {m,n} 前一个字符出现m-n次  AB{1,3}C --> ABC ABBC ABBBC

  贪婪匹配(.*) :在整个表达式匹配成功的前提下,尽可能多的匹配*

  非贪婪匹配(.*?) :在整个表达式匹配成功的前提下,尽可能少的匹配*
4、示例(贪婪模式和非贪婪模式)
  见 :见01_贪婪匹配和非贪婪匹配示例.py
	import re
	s = """<div><p>众芳摇落独喧妍,占尽风情向小园</div></p>
	<div><p>疏影横斜水清浅,暗香浮动月黄昏</div></p>"""
	#创建编译对象,贪婪匹配
	#re.S作用:使.能够以匹配\n在内的所有字符
	#贪婪匹配是.*,
	p = re.compile('<div><p>.*</div></p>',re.S)
	#非贪婪匹配:.*?
	p = re.compile('<div><p>.*?</div></p>',re.S)
	#匹配字符串s
	r = p.findall(s)
	print(r)
5、findall()的分组(重要,但我没听懂)
import re
#解释 :先按照整体匹配出来,然后再匹配()中的
# 如果有2个或者多个(),则以元组的方式取显示

s = "A B C D"
p1 = re.compile('\w+\s+\w+')
print(p1.findall(s))
# ['A B','C D']

p2 = re.compile('(\w+)\s+\w+')
# 第1步 :['A B','C D']
# 第2步 :['A','C']
print(p2.findall(s))

p3 = re.compile('(\w+)\s+(\w+)')
# 第1步 :['A B','C D']
# 第2步 :[('A','B'),('C','D')]
print(p3.findall(s))
 6、练习
import re
s = """<div class = "animal">
    <p class = "name">
        <a title = "Tiger"></a>
    </p>
    <p class = "contents">
        Two tigers two tigers run fast
    </p>
</div>

<div class = "animal">
    <p class = "name">
        <a title = "Rabbit"></a>
    </p>
    <p class = "contents">
        Small white rabbit white and white
    </p>
</div>"""
#正则表达式
p = re.compile('<div class = "animal".*?title = "(.*?)">.*?contents">(.*?)</p>',re.S)
r = p.findall(s)
#print(r)
for animal in r:
    print("动物名称:",animal[0].strip())
    print("动物描述:",animal[1].strip())
7、案例1 :内涵段子脑筋急转弯抓取
  见 :04_内涵段子脑筋急转弯抓取.py
  网址 :www.neihan8.com
  步骤:
    1、找URL规律
 第1页:https://www.neihan8.com/njjzw/
 第2页:https://www.neihan8.com/njjzw/index_2.html
 第3页:https://www.neihan8.com/njjzw/index_3.html
2、用正则匹配出 题目 和 答案
  p = re.compile('<div class="text-.*?title="(.*?)".*?<div class="desc">(.*?)</div>',re.S)
3、写代码
  1、发请求
  2、用正则匹配
  3、写入本地文件
  代码:
import urllib.request
import re

class NeihanSpider:
    def __init__(self):
        self.baseurl = "https://www.neihan8.com/njjzw/"
        self.headers = {"User-Agent":"Mozilla/5.0"}
        self.page = 1
        
    # 下载页面
    def loadPage(self,url):
        req = urllib.request.Request(url,headers=self.headers)
        res = urllib.request.urlopen(req)
        html = res.read().decode("utf-8")
        self.parsePage(html)
        
    # 解析页面
    def parsePage(self,html):
        p = re.compile('<div class="text-.*?title="(.*?)".*?<div class="desc">(.*?)</div>',re.S)
        r_list = p.findall(html)
        # [("什么动物...","海豹"),(),()...]
        self.writePage(r_list)
        
    # 保存页面
    def writePage(self,r_list):
        for r_tuple in r_list:
            for r_str in r_tuple:
                with open("急转弯.txt","a",encoding="gb18030") as f:
                    f.write(r_str.strip() + "\n")
            with open("急转弯.txt","a",encoding="gb18030") as f:
                f.write("\n")
        
    def workOn(self):
        self.loadPage(self.baseurl)
        while True:
            c = input("成功,是否继续(y/n):")
            if c.strip().lower() == "y":
                self.page += 1
                url = self.baseurl + "index_" +\
                      str(self.page) + ".html"
                self.loadPage(url)
            else:
                print("爬取结束,谢谢使用!")
                break
                
if __name__ == "__main__":
    spider = NeihanSpider()
    spider.workOn()
    

    








8、猫眼电影top100榜单,存到csv表格文件中
  网址:猫眼电影 - 榜单 - top100榜
  目标:抓取电影名、主演、上映时间
  1、知识点讲解
    1、csv模块的使用流程
  1、打开csv文件
    with open("测试.csv","a") as f:
  2、初始化写入对象
    writer = csv.writer(f)
  3、写入数据
    writer.writerow(列表)
2、示例 
'''05_csv示例.py'''
import csv

with open("猫眼.csv","a",newline="") as f:
    # 初始化写入对象
    writer = csv.writer(f)
    #把列表写入到文件中
    writer.writerow(["电影名称","主演"])
    writer.writerow(["霸王别姬","张国荣"])
    writer.writerow(["唐伯虎点秋香","周星驰"])

  2、准备工作
    1、找URL
  第1页:http://maoyan.com/board/4?offset=0
  第2页:http://maoyan.com/board/4?offset=10
  第n页:
    offset = (n-1)*10
2、正则匹配
  <div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?releasetime">(.*?)</p>
3、写代码
代码:
'''06_猫眼电影top100抓取.py'''
import urllib.request
import re
import csv

class MaoyanSpider:
    def __init__(self):
        self.baseurl = "http://maoyan.com/board/4?offset="
        self.headers = {"User-Agent":"Mozilla/5.0"}
        self.page = 1
        self.offset = 0
        
    # 下载页面
    def loadPage(self,url):
        req = urllib.request.Request(url,headers=self.headers)
        res = urllib.request.urlopen(req)
        html = res.read().decode("utf-8")
        self.parsePage(html)
        
    # 解析页面
    def parsePage(self,html):
        p = re.compile('<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?releasetime">(.*?)</p>',re.S)
        r_list = p.findall(html)
#        print(r_list)
        # [("霸王别姬","张国荣","1994-01-01"),(),()...]
        self.writePage(r_list)
    
    def writePage(self,r_list):
        if self.page == 1:
            with open("猫眼电影.csv","a",newline="") as f:
                writer = csv.writer(f)
                writer.writerow(["电影名称","主演","上映时间"])
        for r_tuple in r_list:
            with open("猫眼电影.csv","a",newline="") as f:
                # 创建写入对象
                writer = csv.writer(f)
#                L = list(r_tuple)
                L = [r_tuple[0].strip(),r_tuple[1].strip(),r_tuple[2].strip()]
                # ["霸王别姬","张国荣","1994-01-01"]
                writer.writerow(L)
    
    def workOn(self):
        while True:
            c = input("爬取请按y(y/n):")
            if c.strip().lower() == "y":
                self.offset = (self.page-1)*10
                url = self.baseurl + str(self.offset)
                self.loadPage(url)
                self.page += 1
            else:
                print("爬取结束,谢谢使用!")
                break
                
if __name__ == "__main__":
    spider = MaoyanSpider()
    spider.workOn()     
        
        
        
        
        
        
        
        
        

2、Fiddler常用菜单

1)、Inspector : 查看抓到的数据包的详细内容

1、分为请求(request)和响应(response)两部分

2、常用选项

1、Headers :显示客户端发送到服务器的header,包含客户端信息、cookie、传输状态
2、WebForms :显示请求的POST数据 <body>
3、Raw :将整个请求显示为纯文本

3)、请求方式及案例

  1、GET
  2、POST
  3、Cookie模拟登陆
1、什么是cookie、session
  HTTP是一种无连接协议,客户端和服务器交互仅仅限于 请求/响应过程,结束后断开,下一次请求时,服务器会认为是一个新的客户端,为了维护他们之间的连接,让服务器知道这是前一个用户发起的请求,必须在一个地方保存客户端信息。
  cookie :通过在客户端记录的信息确定用户身份
  session :通过在服务端记录的信息确定用户身份
2、案例 :使用cookie模拟登陆人人网
  见 :07_cookie模拟登陆人人网.py
  步骤:
    1、通过抓包工具、F12获取到cookie(先登陆1次网站)
	2、正常发请求
	url:http://www.renren.com/967469305/profile
	代码:
'''07_cookie模拟登陆人人网.py'''
import urllib.request

url = "http://www.renren.com/967469305/profile"
headers = {
        "Host":"www.renren.com",
        "Connection":"keep-alive",
        "Upgrade-Insecure-Requests":"1",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Referer":"http://www.renren.com/",
#        Accept-Encoding: gzip, deflate
        "Accept-Language":"zh-CN,zh;q=0.9",
        "Cookie":"anonymid=jnoaljpk7d3nh2; depovince=BJ; _r01_=1; _de=4DBCFCC17D9E50C8C92BCDC45CC5C3B7; ln_uact=13603263409; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; jebe_key=1b1f4a34-0468-4185-a3b0-6f2c38abc368%7C2012cb2155debcd0710a4bf5a73220e8%7C1540454149943%7C1%7C1540454153787; wp_fold=0; wp=0; jebecookies=2fc339e7-1b51-43ce-bc85-e2dc1f68ee16|||||; JSESSIONID=abcANrnqoMuLshY34pQAw; ick_login=30d0bd58-f6bb-437f-8d0d-6a72ae00e7b7; p=1e1b85cb8dda387a70e400a341c2e9c95; first_login_flag=1; t=4f652cc0a8f3fd50f5c9095c92d4717d5; societyguester=4f652cc0a8f3fd50f5c9095c92d4717d5; id=967469305; xnsid=55bff2d5; loginfrom=syshome"
    }

req = urllib.request.Request(url,headers=headers)
res = urllib.request.urlopen(req)
print(res.read().decode("utf-8"))

'''cookie模拟登录CSDN网'''
import urllib.request

url = "https://i.csdn.net/#/uc/profile"

headers = {
        "Host":"www.csdn.net",
        "Connection":"keep-alive",
        "Upgrade-Insecure-Requests":"1",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36x-requested-with:XMLHttpRequest",
        "Accept":"application/json, text/plain, */*",
        "Referer":"//passport.csdn.net/login?code=public",
#        Accept-Encoding: gzip, deflate
        "Accept-Language":"zh-CN,zh;q=0.9",
        "Cookie":"uuid_tt_dd=10_9868640580-1568772966185-773923; dc_session_id=10_1568772966185.480725; SESSION=2c6a7725-b303-466b-9e16-24802c6d133e; __guid=165585982.4138767749505633000.1568772966482.5442; monitor_count=1; UserName=BTZywl; UserInfo=b28e65a2eb3447e9886eca80ef825a61; UserToken=b28e65a2eb3447e9886eca80ef825a61; UserNick=%E5%8C%85%E5%B0%8F%E5%BD%A4; AU=E46; UN=BTZywl; BT=1568772981929; p_uid=U000000; Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac=1568701652,1568705441,1568715718,1568772986; Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac=1568772986; Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac=1788*1*PC_VC!5744*1*BTZywl!6525*1*10_9868640580-1568772966185-773923; dc_tos=py08zk"
    }
req = urllib.request.Request(url,headers = headers)
res = urllib.request.urlopen(req)
print(res.read().decode("utf-8"))

在这里插入图片描述
这里的url = "https://i.csdn.net/#/uc/profile"是自己的个人中心的网址,刚开始还不知道怎么弄,后来想了一下,试了试这个,竟然对了,还有一个需要改的地方是 “Host”:“www.csdn.net”,最后记得cookie当然是要改的了,多做一两个就明白了,果然睡醒之后的大脑是很聪明的。

4、requests模块

1、安装(用管理员身份去打开Anaconda Prompt)

Anaconda   : conda install requests
Windows cmd: python -m pip install requests
  ## 以管理员身份去执行pip安装命令

2、常用方法

1、get(url,headers=headers) : 发起请求,获取响应对象
2、response属性
  1、response.text :返回字符串类型
  2、response.content : 返回bytes类型
    1、应用场景 :爬取非结构化数据
	2、示例:将网上的图片爬取到本地
	代码:
# -*- coding: utf-8 -*-
"""
Created on Sat Sep 14 16:32:45 2019

@author: aa
"""
import requests
url = "https://media.tenor.com/images/aab76b33f0da6f6841a6c063e3d89e78/tenor.gif"
headers = {"User-Agent":"Mozilla/5.0"}
res = requests.get(url,headers = headers)
html = res.content
with open("易烊千玺.jpg","wb") as f:
    f.write(html)
    
print("图片下载成功")

这里需要注意的是图片的地址并不是导航栏上的地址,而是需要右键—>审查元素–>里面找到图片的地址,不然很可能爬不下来,我爬取大佬的照片的时候就遇到这个小问题了。
3、response.encoding :响应对象编码
一般返回 :ISO-8859-1
response.encoding = “utf-8”
4、response.status_code :返回服务器响应码
5、response.url :返回数据的URL地址
3、get()使用场景
1、没有查询参数
res = requests.get(url,headers=headers)
2、有查询参数: params={}
注 :params参数必须为字典,自动进行编码
见 :09_requests.get.params.py
代码:

'''09_requests.get.params.py'''
import requests

headers = {"User-Agent":"Mozilla/5.0"}
url = "http://www.baidu.com/s?"
key = input("请输入要搜索的内容:")
params = {"wd":key}

# 自动编码,自动拼接URL,params必须为字典
res = requests.get(url,params=params,headers=headers)
# 指定utf-8
res.encoding = "utf-8"
print(res.text)
4、post() 参数名 :data
  1、data = {}
  2、示例 :10_有道翻译post.py
  代码:
'''10_有道翻译post.py'''
import requests
import json

# 请输入你要翻译的内容
key = input("请输入要翻译的内容:")
# post方法要求data为字典格式
data = {"i": key,
        "from":"AUTO",
        "to":"AUTO",
        "smartresult":"dict",
        "client":"fanyideskweb",
        "salt":"1540373170893",
        "sign":"a5d9b838efd03c9b383dc1dccb742038",
        "doctype":"json",
        "version":"2.1",
        "keyfrom":"fanyi.web",
        "action":"FY_BY_REALTIME",
        "typoResult":"false"
    }

# 发请求,获取响应
# url为POST的地址,抓包工具抓到的,此处去掉 _o
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"
headers = {"User-Agent":"Mozilla/5.0"}
# 此处data为form表单数据
res = requests.post(url,data=data,headers=headers)
res.encoding = "utf-8"
html = res.text
# 把json格式字符串转换为Python中字典
r_dict = json.loads(html)
result = r_dict['translateResult'][0][0]["tgt"]
print(result)

Day3*************************************************************************

1、requests模块

1、代理(参数名:proxies)

1、获取代理IP的网站
  西刺代理网站
  快代理
  全网代理
2、普通代理
  proxies = {"协议":"协议://IP地址:端口号"}
183.129.207.82	11597
183.230.177.118	8060
www.whatismyip.com(一天只能访问5次)
查自己电脑上的ip:在终端输入ipconfig
3、私密代理(收费)
  proxies = {"http":"http://309435365:szayclhp@123.206.119.108:21081"}

2、案例1 :爬取链家二手房信息 --> 存到MySQL数据库中

1、找URL
  https://bj.lianjia.com/ershoufang/pg1/
2、正则
<div class="houseInfo".*?data-el="region">(.*?)</a>.*?<div="totalPrice">.*?<span>(.*?)</span>(.*?)</div>
3、写代码
代码:
'''05_链家数据ToMysql.py'''
import requests
import re
import pymysql
import warnings

class LianjiaSpider:
    def __init__(self):
        self.baseurl = "https://bj.lianjia.com/ershoufang/pg"
        self.page = 1
        self.headers = {"User-Agent":"Mozilla/5.0"}
        self.proxies = {"http":"http://309435365:szayclhp@123.206.119.108:16817"}
        self.db = pymysql.connect("localhost",
                  "root","123456",charset="utf8")
        self.cursor = self.db.cursor()

    def getPage(self,url):
        res = requests.get(url,proxies=self.proxies,headers=self.headers,timeout=5)
        res.encoding = "utf-8"
        html = res.text
        print("页面爬取成功,正在解析...")
        self.parsePage(html)

    def parsePage(self,html):
        p = re.compile('<div class="houseInfo".*?data-el="region">(.*?)</a>.*?<div class="totalPrice">.*?<span>(.*?)</span>(.*?)</div>',re.S)
        r_list = p.findall(html)
        # [("天通苑","480","万"),()..]
        print("页面解析完成,正在存入数据库...")
        self.writeTomysql(r_list)

    def writeTomysql(self,r_list):
        c_db = "create database if not exists Lianjiadb \
                character set utf8"
        u_db = "use Lianjiadb"
        c_tab = "create table if not exists housePrice( \
                 id int primary key auto_increment,\
                 housename varchar(50), \
                 totalprice int)charset=utf8"
        
        warnings.filterwarnings("ignore")
        try:
            self.cursor.execute(c_db)
            self.cursor.execute(u_db)
            self.cursor.execute(c_tab)
        except Warning:
            pass

        ins = "insert into housePrice(housename,totalprice) \
               values(%s,%s)"
        for r_tuple in r_list:
            name = r_tuple[0].strip()
            price = float(r_tuple[1].strip())*10000
            L = [name,price]
            self.cursor.execute(ins,L)
            self.db.commit()
        print("存入数据库成功")


    def workOn(self):
        while True:
            c = input("爬取按y(q退出):")
            if c.strip().lower() == "y":
                url = self.baseurl + str(self.page) + "/"
                self.getPage(url)
                self.page += 1
            else:
                self.cursor.close()
                self.db.close()
                print("爬取结束,谢谢使用!")
                break



if __name__ == "__main__":
    spider = LianjiaSpider()
    spider.workOn()
'''06_链家数据ToMongo.py'''
import requests
import re
import pymongo

class LianjiaSpider:
    def __init__(self):
        self.baseurl = "https://bj.lianjia.com/ershoufang/pg"
        self.page = 1
        self.headers = {"User-Agent":"Mozilla/5.0"}
        self.proxies = {"http":"http://309435365:szayclhp@123.206.119.108:16817"}
        self.conn = pymongo.MongoClient("localhost",27017)
        self.db = self.conn.Lianjia
        self.myset = self.db.housePrice

    def getPage(self,url):
        res = requests.get(url,proxies=self.proxies,headers=self.headers,timeout=5)
        res.encoding = "utf-8"
        html = res.text
        print("页面爬取成功,正在解析...")
        self.parsePage(html)

    def parsePage(self,html):
        p = re.compile('<div class="houseInfo".*?data-el="region">(.*?)</a>.*?<div class="totalPrice">.*?<span>(.*?)</span>(.*?)</div>',re.S)
        r_list = p.findall(html)
        # [("天通苑","480","万"),()..]
        print("页面解析完成,正在存入数据库...")
        self.writeTomongo(r_list)

    def writeTomongo(self,r_list):
        for r_tuple in r_list:
            D = {"houseName":r_tuple[0].strip(),\
            "totalPrice":float(r_tuple[1].strip())*10000}
            self.myset.insert(D)
        print("存入数据库成功")

    def workOn(self):
        while True:
            c = input("爬取按y(q退出):")
            if c.strip().lower() == "y":
                url = self.baseurl + str(self.page) + "/"
                self.getPage(url)
                self.page += 1
            else:
                print("爬取结束,谢谢使用!")
                break



if __name__ == "__main__":
    spider = LianjiaSpider()
    spider.workOn()

3、Web客户端验证(参数名:auth)

1、auth=("用户名","密码")(元组的方式)
   auth=("tarenacode","code_2013")
2、案例 :09_Web客户端验证.py
代码:
'''09_Web客户端验证.py'''
import requests
import re

class NoteSpider:
    def __init__(self):
        self.headers = {"User-Agent":"Mozilla/5.0"}
        self.url = "http://code.tarena.com.cn/"
        self.proxies = {"http":"http://309435365:szayclhp@123.206.119.108:16817"}
        # auth参数存储用户名和密码(必须为元组)
        self.auth = ("tarenacode","code_2013")
    
    def getParsePage(self):
        res = requests.get(self.url,
                           proxies=self.proxies,
                           headers=self.headers,
                           auth=self.auth,
                           timeout=3)
        res.encoding = "utf-8"
        html = res.text
        print(html)
        p = re.compile('<a href=".*?>(.*?)</a>',re.S)
        r_list = p.findall(html)
        print(r_list)
        self.writePage(r_list)
        
    def writePage(self,r_list):
        print("开始写入文件...")
        with open("达内科技.txt","a") as f:
            for r_str in r_list:
                f.write(r_str + "\n\n")
        print("写入成功")
    
if __name__ == "__main__":
    spider = NoteSpider()
    spider.getParsePage()

4、SSL证书认证(参数名:verify)

数字证书认证中心
1、verify = True : 默认,进行SSL证书认证
2、verify = False: 不做认证

代码:

import requests
url = "https://www.12306.cn/mormhweb/"
headers = {"User-Agent":"MOzilla/5.0"}

res = requests.get(url,headers = headers,verify = False)
res.encoding = "utf-8"
print(res.text)

2、urllib.request中Handler处理器

1、定义

自定义的urlopen()方法,urlopen()方法是一个特殊的opener(模块已定义好),不支持代理等功能,通过Handler处理器对象来自定义opener对象

2、常用方法

1、build_opener(Handler处理器对象) :创建opener对象
2、opener.open(url,参数)

3、使用流程

1、创建相关的Handler处理器对象
  http_handler = urllib.request.HTTPHandler()
2、创建自定义opener对象
  opener = urllib.request.build_opener(http_handler)
3、利用opener对象打开url
  req = urllib.request.Request(url,headers=headers)
  res = opener.open(req)

4、Handler处理器分类

1、HTTPHandler() :没有任何特殊功能
2、ProxyHandler(普通代理)
  代理: {"协议":"IP地址:端口号"}
3、ProxyBasicAuthHandler(密码管理器对象) :私密代理
4、HTTPBasicAuthHandler(密码管理器对象) : web客户端认证
5、密码管理器对象作用
  1、私密代理
  2、Web客户端认证
  3、程序实现流程
    1、创建密码管理器对象
  pwdmg = urllib.request.HTTPPasswordMgrWithDefaultRealm()
	2、把认证信息添加到密码管理器对象
  pwdmg.add_password(None,webserver,user,passwd)
	3、创建Handler处理器对象
		1、私密代理
    proxy = urllib.request.ProxyAuthBasicHandler(pwdmg)
		2、Web客户端
    webbasic = urllib.request.HTTPBasicAuthHandler(pwdmg)

安装:

1、Windows :安装selenium

Anaconda Prompt下执行 : 
    python -m pip install selenium

2、Ubuntu :安装Scrapy框架

#### 依赖库较多,以下为全部依赖库,有些已安装 ####
1、sudo apt-get install libssl-dev
   sudo apt-get install libffi-dev 
   sudo apt-get install python3-dev
   sudo apt-get install build-essential
   sudo apt-get install libxml2
   sudo apt-get install libxml2-dev
   sudo apt-get install libxslt1-dev
   sudo apt-get install zlib1g-dev
2、sudo pip3 install Scrapy

Day04****************************************************************

1、xpath工具(解析)

1、xpath

本来是在XML文档中查找信息的语言,同样适用于HTML文档的检索

2、xpath辅助工具

1、Chrome插件 :XPath Helper
  1、打开 :Ctrl + Shift + X
  2、关闭 :Ctrl + Shift + X
2、Firefox插件 :XPath checker
3、XPath表达式编辑工具 :XML quire

3、xpath匹配规则

1、匹配演示
  1、查找bookstore下所有节点:/bookstore
  2、查找所有的book节点://book
  3、查找所有book下的title节点中,lang属性为"en"的节点
    //book/title[@lang="en"]
  4、查找bookstore下的第2个book节点下的title节点:
    /bookstore/book[2]/title/text()
2、选取节点
  /  : 从根节点开始选取 
  // : 从整个文档中查找节点
       //price  、  /bookstore/book//price
  @  : 选取某个节点的属性
       //title[@lang="en"]
3、 @的使用
  1、选取1个节点 : //title[@lang="en"]
  2、选取N个节点 : //title[@lang]
  3、选取节点的属性值 : //title/@lang
<a class=....,src="http://..."
4、匹配多路径
  1、符号 : |
  2、获取所有book节点下的 title节点和price节点
    //book/title | //book/price
5、函数
  1、contains() : 匹配一个属性值中包含某些字符串的节点
  //title[contains(@lang,"e")]
  2、text() 
    //title[contains(@lang,"e")]/text()

2、lxml库及xpath使用

1、lxml库 :HTML/XML解析库

1、安装 
  python -m pip install lxml
  conda install lxml
2、使用流程
  1、导模块
    from lxml import etree
  2、利用lxml库的etree模块创建解析对象
    parseHtml = etree.HTML(html)
  3、解析对象调用xpath工具定位节点信息
    r_list = parseHtml.xpath('xpath表达式')
### 只要调用了xpath,结果一定是列表 ###
3、示例 :见01_xpath示例.py
4、如何获取节点对象的内容
  节点对象.text
5、案例1 :抓取百度贴吧帖子里面所有的图片
  1、目标 :抓取指定贴吧所有图片
  2、思路
    1、获取贴吧主页URL,下一页:找URL规律
	2、获取1页中每个帖子的URL
	3、对每个帖子URL发请求,获取帖子里图片URL
	4、对图片URL发请求,以wb方式写入本地文件
  3、步骤
    1、获取贴吧主页URL
  http://tieba.baidu.com/f? + 查询参数
2、找到页面中所有帖子的URL
  src : 完整链接
  href : 和主URL进行拼接
    /p/5926064184 千玺:p/6242828073
        http://tieba.baidu.com/p/5926064184
  xpath匹配链接:
   写法1: //div[@class="col2_right j_threadlist_li_right"]/div/div/a/@href

   写法2(推荐): //div[@class="t_con cleafix"]/div/div/div/a/@href
	(好像是错的)千玺://div[@class="d_post_content j_d_post_content  clearfix"]
	微博://div[@box-result clearfix hover]/a/@href
3、找每个帖子中图片URL
  Xpath匹配:
    //img[@class="BDE_Image"]/@src
	
	千玺://ima[@class="left_img"]/@src
4、代码实现
6、案例2 :糗事百科(详情页)-xpath
  1、目标 :用户昵称、段子内容、好笑数、评论数
  2、步骤
    1、找URL
  https://www.qiushibaike.com/8hr/page/1/
2、xpath匹配
  1、基准xpath://div[contains(@id,"qiushi_tag_")]

    用户昵称: ./div/a/h2
    段子内容: .//div[@class="content"]/span
    好笑数量: .//i
    评论数量: .//i
'''02_百度贴吧图片抓取案例.py'''
import requests
from lxml import etree
import time

class BaiduImageSpider:
    def __init__(self):
        self.headers = {"User-Agent":"Mozilla/5.0"}
        self.baseurl = "http://tieba.baidu.com"
        self.pageurl = "http://tieba.baidu.com/f?"
        
    # 获取所有帖子URL列表
    def getPageUrl(self,params):
        res = requests.get(self.pageurl,params=params,headers=self.headers) 
        res.encoding = "utf-8"
        html = res.text
        # 构建解析对象
        parseHtml = etree.HTML(html)
        # 帖子链接列表
        t_list = parseHtml.xpath('//div[@class="t_con cleafix"]/div/div/div/a/@href')
        # t_list : ['/p/233432','/p/2039820',..]
        print(t_list)
        for t_link in t_list:
            # 拼接帖子完整链接
            t_link = self.baseurl + t_link
            self.getImageUrl(t_link)
    
    # 获取帖子中图片URL列表
    def getImageUrl(self,t_link):
        res = requests.get(t_link,headers=self.headers)
        res.encoding = "utf-8"
        html = res.text
        # 构造解析对象
        parseHtml = etree.HTML(html)
        img_list = parseHtml.xpath('//img[@class="BDE_Image"]/@src')
        print(img_list)
        for img_link in img_list:
            self.writeImage(img_link)
    
    # 保存到本地
    def writeImage(self,img_link):
        # 获取图片的bytes
        res = requests.get(img_link,headers=self.headers)
        res.encoding = "utf-8"
        html = res.content
        # filename
        filename = img_link[-12:]
        with open(filename,"wb") as f:
            f.write(html)
            time.sleep(0.5)
            print("%s下载成功" % filename)
    
    # 主函数
    def workOn(self):
        name = input("请输入贴吧名:")
        begin = int(input("请输入起始页:"))
        end = int(input("请输入终止页:"))
        
        for n in range(begin,end+1):
            pn = (n-1)*50
            params = {
                    "kw":name,
                    "pn":str(pn)
                }
            self.getPageUrl(params)
            
if __name__ == "__main__":
    spider = BaiduImageSpider()
    spider.workOn()

这个代码我爬取了千玺的图片,但其中有很多其他的图片,是这样的。
在这里插入图片描述
中间有一些其他的,我也不知道哪来的,在页面上也没显示。
爬取王俊凯的就没有这样,就全是图片
在这里插入图片描述
需要注意的就是抓取的代码需单独保存在一个文件夹里面,不然爬下来的图片会很凌乱。

#03_糗事百科(详情页)-xpath
import requests
from lxml import etree
import pymongo
class QuishiSpider:
    def __init__(self):
        self.url = "https://www.qiushibaike.com/8hr/page/1/"
        self.headers = {"User-Agent":"Mozilla/5.0"}
        self.conn = pymongo.MongoClient("localhost",27017)
        self.db = self.conn.Baikedb
        self.myset = self.db.baikeset
    
    def getPage(self):
        res = requests.get(self.url,headers = self.headers)
        res.encoding = "utf-8"
        html = res.text
        self.parsePage(html)
        
    def parsePage(self,html):
        parseHtml = etree.HTML(html)
        #基准xpath,匹配每个段子的列表
        base_list = parseHtml.xpath('//div[contains(@id,"qiushi_tag_")]')
        
        #遍历每个段子的节点对象(base)
        for base in base_list:
            #用户昵称
            uername = base.xpath('./div/a/h2')
            if len(username) == 0:
                username = "匿名用户"
            else:
                username = username[0].text
                
            #段子内容
            content = base.xpath('.//div[@class="content"]/span')[0].text
            #好笑数量
            #[<element.好笑数量>,<element.评论>]
            laughNum = base.xpath('.//i')[0].text
            
            #评论数量
            pingNum = base.xpath('.//i')[1].text
            
            #定义为字典,存入数据库
            d = {
                    "username":username.strip(),
                    "content":content.strip(),
                    "laughNum":laughNum.strip(),
                    "pingNum":pingNum.strip()
                    }
            self.myset.insert(d)
            pirnt("存入数据库成功")
        
    
if __name__ =="__main__":
    spider = QuishiSpider()
    spider.getPage()

爬虫基础就这样学完了,虽然还有一些值得我无仔细思量的地方,但是时间不等人,只能边学后面的边复习前面的了,加油。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值