前言
没啥说的,一句话就是想学。有人说程序员的寿命不超过35,但作为一个过完年就30岁的我,就是不服,不信,不想任命。另外,我觉的学习,真的不一定就得为了就业,或者为了创造价值和财富,我就是想能学到一点儿知识,就是想万一哪天能用到。
我是做测控设备的软件开发,用的是Labview,好多人应该都不知道这种语言。Labview入门很简单,上手很快,各种串口,网口随便通讯。(扯远了。。)有一天,经理让公司一个同事查竞标网上相关“***”的信息,说最好把两年内的所有信息都找到。然后同事用两天时间,在那个竞标网上以关键字搜索。
我当时就想能不能使用爬虫,将这些信息爬下来啊。网上就找了一圈,发现还真有已经写好的爬虫。于是,我就动了自己学习的念头。(因为我有一点儿python的基础,也写过HTML)
从现在开始,就记录我的爬虫学习。
爬虫的流程
爬虫一般分为三个过程:获取网页、解析网页(提取数据)、存储数据
这是我画的一个爬虫流程脑图,就按照这个开始学习。
爬取静态网页
静态网页是最好爬取的网页。
比如豆瓣电影的TOP250网页就是静态展示。
这是在网上随便查了一下,来源:IIS7 站长之家
1)静态网页:静态网页是以.html、.htm、.html、.shtml、.xml作为后缀的网页。静态网页的内容是固定的,每个页面都是独立的页面不会根据浏览者的不同需求而改变。
2)动态网页:使用ASP 或PHP 或 JSP 等作为后缀的网页。动态网页以数据库技术为基础,可以大大降低网站维护的工作量。
刚起步阶段,知道这些就够了,在你不断实践过程中,我觉就会摸索出一套自己的理论了(另外说一声,爬虫要遵守Robots协议)
步骤:
1.安装requests第三方库
网上很多资料,我反正是用Pycharm写,在set设置中,很容易安装;使用pip installs requsests也没毛病。
2.安装bs4第三方库
3.写程序
其实上网的原理和其他通信原理一样,你先发送请求,让后对方响应,接着给你返回数据。
所以爬静态网页(以及动态网页都是),先请求它。
请求的方式有get和post两种。
无论是get请求还是post请求,都需要传入url(网址)。
获取网页
1、get请求
假如网址是
url = “https://www.baidu.com/s?wd=美女”
这里有一个查询:wd=美女
方法一:
r = requests.get(url)
方法二:
先将需要查询的键和值保存到一个字典中,然后使用params构建到URL中。
key_value = {'wd':'美女'}
r = requests.get('https://www.baidu.com/s?',params=key_value)
很多网站会反爬虫,所以你要伪装爬虫,假装我是用浏览器查看的,所以要定制请求头。
所以上面的代码应该写成
#定义请求头的浏览器代理,伪装成浏览器
headers = {'user-agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
#请求
r = requests.get(url,headers=headers,timeout=20)
#或者
r = requests.get('https://www.baidu.com/s?',params=key_value,headers=headers,timeout=20)
2、POST请求
有时还需要发送一些编码为表单形式的数据,如在登录的时候请求就为POST,因为如果用GET请求,密码就会显示在URL中,这是非常不安全的。如果要实现POST请求,只需要简单地传递一个字典给Requests中的data参数,这个数据字典就会在发出请求的时候自动编码为表单形式。
另外,你也能不给data参数赋值。例如,我就是想请求前面那个网址,一样用。
link = 'https://www.baidu.com/s?wd=美女'
#定义请求头的浏览器代理,伪装成浏览器
headers = {'user-agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
#请求、响应
r = requests.post(link,headers=headers,timeout=20)
解析网页
#################解析网页##################
soup = BeautifulSoup(r.text,'html.parser')
网上说在旧版本的lxml库中,使用’lxml’解析,没问题,但新版本中语法改变(有时间研究看看),所以使用‘html.parser’解析器,该解析器是python内置解析器。
soup中保存了这个网页内容,这时候你就又要使用浏览器的检查功能(ctrl+shift+i),查看想要的数据在那。
比如,我想爬class为post-title的h1标签下的a标签的文本
title = soup.find('h1',class_='post-title').a.text.strip()
这是BeautifulSoup的find()方法,以后还有很多中定位元素的方法。
存储数据
文本数据就是txt,csv保存喽
###############存储数据——TXT#####################
with open('Data/LearnScrapy_1.txt','w') as file:
file.write(title)
实战——爬取图片
网页:http://desk.zol.com.cn/bizhi/1042_12606_2.html
可以发现,是静态网页,另外每张图片所在网址都是1042_XXX_2
比如第一张是1042_12606_2,第二张就是1042_12607_2
首先导入三个库
import requests #用于请求
from bs4 import BeautifulSoup #用于解析网页
import urllib.request as download #用于下载图片
制作url
先从http://desk.zol.com.cn/bizhi/1042_12606_2.html爬起,所以设定一个起始值
#起始值
begin_num = 12606
#设置url
link = 'http://desk.zol.com.cn/bizhi/1042_'+str(begin_num)+'_2.html'
定义请求头
#定义请求头的浏览器代理,伪装成浏览器
headers = {
'user-agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6',
'host':'desk.zol.com.cn'
}`
请求网页,获得所有HTML
#请求
r = requests.get(link,headers=headers,timeout=20)
提取数据
所以img在class为photo的div标签下的第一个div中
#################提取需要的数据##################
soup = BeautifulSoup(r.text,'html.parser')
img_src = soup.select('div.photo > div:nth-of-type(1) > img')[0].get('src')
另外获得img标签中的src属性方法是img[0].get(‘src’)
保存数据——图片下载
download.urlretrieve(img_src,'./img/%s.jpg' % begin_num)
OK,整个过程就是这样,完整代码如下:
#! /usr/bin/python
# coding: utf-8
import requests
from bs4 import BeautifulSoup
import urllib.request as download
#起始值
begin_num = 12606
################获取网页####爬10张图片###########
for i in range(10):
link = 'http://desk.zol.com.cn/bizhi/1042_'+str(begin_num)+'_2.html'
#定义请求头的浏览器代理,伪装成浏览器
headers = {
'user-agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6',
'host':'desk.zol.com.cn'
}
#请求
r = requests.get(link,headers=headers,timeout=20)
#################提取需要的数据##################
soup = BeautifulSoup(r.text,'html.parser')
img_src = soup.select('div.photo > div:nth-of-type(1) > img')[0].get('src')
download.urlretrieve(img_src,'./img/%s.jpg' % begin_num)
#切换网址
begin_num += 1
print(i)