我…我…我是看着好久没更新Python的文章了,于是我将魔爪伸向了Python来水一文
准备工作
在开始干爬虫之前你肯定要安装Python的环境,也就是Python语言的解释器,还有Python的编辑器,Pycharm。这些之前都有说过,可以参考之前的分类文章
为了能够敏捷而又不失优雅地完成这次操作,我慎(tou)重(lan)选择了直接进行实战演练,废话不多说,开干
分析豆瓣URL
写爬虫之前肯定是要分析链接的,不然你怎么去爬,而且爬取数据我们尽量去找一些返回json数据的URL,因为json更好处理数据,但是并不是所有的站点返回数据都是json
怎么找返回json的URL呢?
- 打开浏览器的抓包工具,查看网络请求,当然你也可以使用FD等这些专业的工具
- 把浏览器网页切换到手机版
国产剧 – 电视 – 豆瓣的URL:https://m.douban.com/tv/chinese
然后我们按下F12打开浏览器的抓包工具,查看network这一栏就可以看到有一条这样的请求
items?os=ios&for_mobile=1&callback=jsonp1&start=0&count=18&loc_id=108288&_=1527155131544
点击它,看它的Request URL:
https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_domestic_hot/items?os=ios&for_mobile=1&callback=jsonp1&start=0&count=18&loc_id=108288&_=1527155131544
我们会发现我们访问的URL跟他请求是URL不同,然后我们查看它的Response就会看到一些json数据
美剧 – 电视 – 豆瓣的URL:https://m.douban.com/tv/american
美剧的Request URL:
https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_american_hot/items?os=ios&for_mobile=1&callback=jsonp1&start=0&count=18&loc_id=108288&_=1527154794289
分析一下这两个URL
/filter_tv_domestic_hot/是根据这个参数来判断电视剧的类型,strat的值也会变,这个表示我们已经获取的数量
请求这个URL能够返回一个json字符串,我们能够将它转换为一个Python字典,就能够从中提取数据了,但是我们发现这个请求返回的数据中有一个jsonp1,这个jsonp1中间包括的才是一个字典,而外面这个jsonp1并不是我们所需要的数据
无论在爬其他网站的时候还是爬豆瓣的时候,如果发现返回的数据包含这个jsonp1、jsonp2…99在前面的时候,说明它的URL参数包含callback=jsonp1,要解决这个问题的话,我们就将这个参数删除掉,就可以将响应变成一个非常完美的json字符串
构建代码
骚气的分析了这么多,下面开始代码,新建一个py文件
定义一个run方法,主要实现我们的逻辑,先写一下我们的思路
def run():
#1.url_list 带请求的是临时地址
#2.发送请求 获取响应
#3.提取数据
#4.保存
然后进行异常处理+请求数据
from retrying import retry
@retry(stop_max_attempt_number=3)
def _parse_url(url):
print("*"*100)
r = requests.get(url,headers=headers,timeout=5) #可能会超时报错
assert r.status_code == 200 #可能会请求不成功报错
return r.content.decode()
def parse_url(url):
try:
html = _parse_url(url)
except Exception as e:
print("报错了:",e)
html = None
return html
完整的代码如下
import json
import requests
from retrying import retry
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Referer":"https://m.douban.com/tv/american"}#referer 豆瓣新加的
@retry(stop_max_attempt_number=3)
def _parse_url(url):
print("*"*100)
r = requests.get(url,headers=headers,timeout=5) #可能会超时报错
assert r.status_code == 200 #可能会请求不成功报错
return r.content.decode()
def parse_url(url):
try:
html = _parse_url(url)
except Exception as e:
print("报错了:",e)
html = None
return html
def get_url_list():#1.url_list 带请求的是临时地址
url_list = [
{
"url_temp":"https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_american_hot/items?os=ios&for_mobile=1&start={}&count=18",
"country":"UK"
},
{
"url_temp":"https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_english_hot/items?os=ios&for_mobile=1&start={}&count=18",
"country": "US"
},
{
"url_temp": "https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_domestic_hot/items?os=ios&for_mobile=1&start={}&count=18",
"country": "China"
}
]
return url_list
def get_content_list(json_response):
dict_response = json.loads(json_response)
content_list = dict_response["subject_collection_items"]
total_num = dict_response["total"]
return content_list,total_num
def save_content_list(content_list):
for content in content_list:
print(content)
print("*"*100)
def run():
#1.url_list 带请求的是临时地址
url_list_temp = get_url_list()
for temp in url_list_temp:
num = 0
total_num = 100
while num<=total_num+18:
url = temp["url_temp"].format(str(num))
#2.发送请求 获取响应
json_response = parse_url(url)
#3.提取数据
content_list,total_num = get_content_list(json_response)
#4.保存
for content in content_list: #添加国家信息
content["country"] = temp["country"]
save_content_list(content_list)
num += 18
if __name__ == '__main__':
run()
反爬虫一些问题
有时候可能爬取不出来数据,这就说明豆瓣进行了升级或者你的爬虫被封禁了
单个ip单个用户在短时间内请求网站数据过快,都会被豆瓣的反爬虫机制发现并判断为机器操作而封禁,解决的方法有几种
1.使用ip代理池,隔一段时间随机换一个ip
2.降低爬取速度,设置爬虫间隔时间
3.将爬取内容分块,分时间段爬取
豆瓣看到马上搞了一个反爬虫,嘿嘿
@素材火 豆瓣小组有api,请求一次就能拿到。。。
手动膜拜大佬,我的基础看完估计已经过年了
听说0评论很尴尬,我来看看,随便问一下能做成wordpress页面调用豆瓣影视列表吗?
@橘子书 可以用PHP去写一个 😎
@沈唁 你赶紧写一个。分享到7p群里。