今天给大家介绍一个有趣的新技术——爬虫。首先来讲一下啥是爬虫。
爬虫也叫网络爬虫,是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。通俗的来讲,爬虫就是一段程序,它来根据你的设定自己去互联网上浏览网页并把这些信息下载下来,然后在从中提取出有用的信息。这些信息可以用在做数据分析、数据统计等等。
接下来我会用通俗的语言来讲解爬虫技术,这些都是基于我个人的理解所写的,水平有限,若有不对的地方请指正。
我们平常浏览的众多网站都是有对应的源代码的。如果你有兴趣,可以用你电脑的任意浏览器打开一个网站,然后按一下F12试试。此时你会看到:网页里所有的文字、图像、声音等等一切元素,都是由HTML源码编排而成。你打开的这个窗口其实就是网页源码的调试窗口,当你试着用鼠标在那些源码上移动时,你会发现每移动到一个地方,网页便会有对应的地方高亮起来。也就是说,当我们把这些被高亮的元素的源码下载下来并解析出来,我们便获取了这些元素。这便是爬虫程序要干的事儿。
既然我们需要下载源码,那我们首要的便是访问这个网站。这里会出现一些问题:因为有些网站有反爬虫技术,它会识别出你是爬虫程序,并中断你的访问甚至是封锁你的IP地址。这其中一个应对方法就是我们的爬虫程序里一定要写好HTTP请求头。HTTP请求头是当你正常用浏览器打开网页时,浏览器向网络服务器发送的一些配置信息和属性。我们就是用这个HTTP请求头来伪装成人类访问用户,以防止被服务器屏蔽。
如何构造合理的 HTTP请求头?
请求头可以通过“requests”模块自定义,例如
headers = {'User-Agent' :
'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D)'
' AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19'}
headers = {'User-Agent': 'Chrome/68.0.3440.106',
'Accept-Encoding': 'gzip, deflate',
'Accept': '*/*',
'Connection': 'keep-alive',
'Content-Length': '18',
'Content-Type': 'application/x-www-form-urlencoded'}
经我亲身测试发现,HTTP请求头包含的这些内容里最为重要的是“User-Agent“这个参数。我们在设置请求头时,其实只需要设置好它就足够了。除了以上这个设置方法,还有一个较为简单的办法,那就是用python的fake_useragent模块来设置,示例代码如下:
#调用模块的UserAgent类方法
from fake_useragent import UserAgent
#实例化类方法
user_agent = UserAgent()
#选择chrome浏览器为User-Agent的值
headers = {'User-Agent':user_agent.chrome}
#选择ie浏览器为User-Agent的值
headers = {'User-Agent':user_agent.ie}
#选择firefox浏览器为User-Agent的值
headers = {'User-Agent':user_agent.firefox}
#随机选择一款浏览器为User-Agent的值
headers = {'User-Agent':user_agent.random}
请求头设置完之后,我们便可以进行下一步关键性的操作——爬取指定网页信息。
如何爬取指定网页的信息?
这次我们用到了requests模块中的get方法,requests.get(url , headers)。通过给get方法传递网址参数url和Http头信息headers便可以接收到网站的响应response,这个response里包含着整个网页的全部源代码。这里我们应该在代码中写好各种可能发生的情况,以此来提高代码运行时的稳定性,防止崩溃。示例代码如下:
from requests.exceptions import ReadTimeout
try:
response = requests.get(url, headers=headers, timeout=0.5)
if response.status_code == 200:
return response.text
return 404
except ReadTimeout:
print('timeout')
except Exception as e:
print(e)
示例中用的是python的异常处理标识符——try、except。首先导入了requests模块中的异常处理类型ReadTimeout,用来处理网站访问超时响应问题。其次Exception用来处理其他常规的问题。然后在判断response参数的status_code的值是否是200,这个值是200说明服务器响应成功了,如果不是,则返回404代码。表示404 NotFound服务器响应失败。到这一步,我们便完成了爬取网页信息的工作,接下来就是从这些网页代码里分析和获取有用信息。
如何从网页源码中获取有用的信息?
这里我们会用到re模块的两个方法,一个是re.findall( 模式(正则表达式), 目标字符串),返回值为list类型,另一个是re.sub(要替换的字符,替换后字符,目标字符串,替换个数),返回值为str类型。re.findall函数是通过指定的正则表达式来匹配出需要的HTML源码,一般情况下是匹配源码中的div容器,也就是类似“
import re
response = """
partten = r'
data = re.findall(partten, response,)
print(data)
data_clean = re.sub(r'|', '', data[0])
print(data_clean)
输出结果为
['太阳是太阳 系的中心天体,占有太阳系总体质量的99.86%。']
太阳是太阳系的中心天体,占有太阳系总体质量的99.86%。
第一行是findall函数的输出结果。从内容上看,我们已经获取了div容器里的内容,但是很明显,这里面掺杂着其他的标记语言和。于是第二步sub函数将其中的和标签替换成了空字符串。这行输出结果便是我们所需要的有用信息。
下面我们来尝试爬取京东官网的手机图片,以下是源码
import urllib.request
import re
from fake_useragent import UserAgent
import requests
from requests.exceptions import ReadTimeout
import os
user_agent = UserAgent()
headers = {
"User-Agent": user_agent.chrome,
}
def get_html(url, req=None):
if req:
url = url + req
else:
url = url
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
#print(response.text)
return response.text
return 404
except ReadTimeout:
print('timeout404')
except Exception as e:
print(e)
def get_request(response):
if response == 404:
return '服务器响应失败!'
else:
try:
partten = r''
data = re.compile(partten).findall(response)
return data
except IndexError:
print('未搜到有用信息')
def output(data):
if not os.path.exists('texts'):
os.mkdir('texts')
for index, inf in enumerate(data):
image_url = 'https://' + inf
image_byte = requests.get(url=image_url, headers=headers).content
with open("./texts/{}.jpg".format(index),'wb') as f:
f.write(image_byte)
print('\n第{}张图片已下载保存成功...'.format(index))
print('\n总共{}张图片已成功下载至texts文件夹中'.format(len(data)))
def main(req):
url = 'https://list.jd.com/list.html?cat=9987,653,655&page='
html = get_html(url, req)
data = get_request(html)
output(data)
if __name__ == '__main__':
req = input('请输入要下载的页码: ')
main(req)
程序运行之后,我们按照提示输入页码,程序便开始下载图片
下载完成之后,我们打开指定的文件夹查看一下效果
大功告成!