本文旨在科普,用最简单明了的语言引导初学者接触爬虫,不求严谨。看到不懂的或者不想懂的专有名词不要纠结,只要代码没问题就继续下去,等爬取成功了再回头抠细节。
我将以虎扑火箭专区为例,爬取火区前一百页的标题。
(实在不喜欢火箭的可以用其它球队哈)
最先要说明的是,Python爬虫非常简单!(当然是指入门)
Python的语法简单
Python有很强大的模块供我们调用
好了,直入主题吧!
导入三个模块
requests 用来发送请求(发送了请求,服务器才会响应你,你的浏览器才有内容显示)
pyquery 用来解析页面
fake_useragent 用来伪造请求头(相当于身份证)
import requests
from pyquery import PyQuery as pq
from fake_useragent import UserAgent
火箭专区地址:https://bbs.hupu.com/rockets
我们直接用requests发送get请求
url = 'https://bbs.hupu.com/rockets'
r = requests.get(url)
print(r)
这个r就是HTTP状态码,我们最常见的404也是状态码
print(r.text)
爬取页面就搞定了,不过出来的都是源码,我们要筛选出想要的信息
要解析页面,必须先要了解一下页面的结构,我们先去火箭专区,然后右键第一个标题,检查(以chrome浏览器为例,360浏览器好像是审查元素)
Elements面板下展示的内容,就是网页的DOM节点和CSS样式,简单说就是网页的结构和内容,按小三角可以折叠和展开,鼠标放在代码上面,左边会高亮对应的内容,双击代码可以直接编辑。
...
class='for-list'
这样带等号的叫做属性,有点像python的字典,等号左边是属性名,右边是属性值经过观察,我们会发现每个帖子信息都在li标签里面
而标题内容都在class属性为truetit的a标签里面
下面简单粗暴地说下pyquery的语法(细讲的话要另起一文了)
标签直接写,
class属性前面加个点,
id属性前面加个#
空格表示嵌套关系(也就是子孙节点)
(结合下面代码理解)
#初始化,先让pyquery认识它,才能解析它
doc = pq(r.text)
#class属性为for-list的ul标签 下面的li标签
#因为我们要分别取出每个li标签的内容,所以要加上items方法方便遍历
info = doc('ul.for-list li').items()#
#对每个li标签,提取它嵌套的class属性为truetit的a标签的内容
#获取文本用text方法
for i in info:
title = i('a.truetit').text()
print(title)
成功了!
既然成功爬取了第一页,我们就试试爬前十页
要有网址才能爬取,所以我们先要解决网址的问题,常规思路是提取网站下一页的链接,但是虎扑的下一页其实是javascript渲染的。而我们用requests直接发送get请求得到的是未经渲染的原始信息。js渲染这种高级的东西我们目前无法解决,但我们通过点击下一页网址可以发现
第一页:https://bbs.hupu.com/rockets
第二页:https://bbs.hupu.com/rockets-2
第三页:https://bbs.hupu.com/rockets-3
似乎横杠后面的数字就是页数
我们试试-1,-10能不能转到第一页和第十页,结果是能的
所以我们就通过这个取巧的方法得到了前十页的网址
把我们之前的代码封装成函数
def get_title(n):
url = f'https://bbs.hupu.com/rockets-{n}'
r = requests.get(url)
doc = pq(r.text)
info = doc('ul.for-list li').items()
for i in info:
title = i('a.truetit').text()
print(title)
然后在1-10遍历一下
for i in range(11):
get_title(i)
十页标题就哗哗哗地爬出来了
但我们的目标是要爬100页的
照葫芦画瓢把range(11)改成range(101)不就可以了?
*for i in range(11):
get_title(i)
事实证明是不行的,出来的还是前十页的标题,那问题出在哪呢?
之前我们得到结论,横杠后面的就是页数,难道第十页之后网址变了?
于是我们打开浏览器,试着打开https://bbs.hupu.com/rockets-20
发现浏览器跳转到了登录界面,也就是说不登录是看不到10页以后的内容的
所以我们就要涉及到一个爬虫的基础知识了:headers(头部信息)
打开https://bbs.hupu.com/rockets-10
右键检查,进入network面板,这里记录了从发起网页页面请求后,分析HTTP请求后得到的各个请求资源信息
找到rockets-10,右边的headers面板记录了头部信息
General 概况,重点:请求地址,方法,状态
Response Headers 响应头,重点:响应内容类型
Request Headers 请求头 重点: user-agent,cookie
一般来说,构建headers的时候,user-agent是必要的,相当于你的身份信息,告诉服务器你是谁
所以我们之前的爬虫里我们的身份是什么呢
#返回请求头信息
print(r.request.headers)
这就相当于告诉服务器,我是python的requests模块,我来找你了,大多数网站看到“非正常浏览器“的身份都不会返回数据给你的,所以我们要假装成是正常浏览器
我们在刚刚的headers面板里可以看到自己的user-agent的信息,可以复制下来,requests请求的时候加上个参数headers,
headers = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
url = 'https://bbs.hupu.com/rockets-10'
r = requests.get(url,headers=headers)
但是复制粘贴还是略麻烦,我们可以用fake_useragent来伪造个user-agent
from fake_useragent import UserAgent
ua = UserAgent()
print(ua.random)
当然,这样我们还是无法得到第十一页的标题,因为我们在浏览器上输入第十一页的网址的时候,就弹出登录界面,用浏览器访问就相当于是正常浏览器身份了,所以不是user-agent的问题
难道每次我们都要手动登录才能爬吗?有没有方便点的方法?这种情况我们就要用上cookie了
首先我们要老老实实地手动登陆一次,这是避免不了的,然后打开https://bbs.hupu.com/rockets-10,右键检查,找到rockets-10的请求头信息,找到cookie,添加到headers里
ua = UserAgent()
headers = {'user-agent':ua.random,
'cookie':'把你的cookie粘贴过来'}
url = f'https://bbs.hupu.com/rockets-{n}'
r = requests.get(url,headers=headers)
添加了cookie,尝试一下
for i in range(101):
get_title(i)
联系客服