本文章属于爬虫入门到精通系统教程第八讲
本次我们会讲解两个知识点
本次我们要抓取的是花瓣网美女照片美女花瓣,陪你做生活的设计师(发现、采集你喜欢的美女图片)花瓣网(http://huaban.com/favorite/beauty/)
scrapy/parsel (https://github.com/scrapy/parsel)(假如你用过scrapy,那么一定不陌生,这就是其中提取器)
Parsel is a library to extract data from HTML and XML using XPath and CSS selectors
简单来讲就是集成了xpath和css,只要你会xpath的话,那么用法没有什么区别
>>> from parsel import Selector >>> sel = Selector(text=u"""<html> <body> <h1>Hello, Parsel!</h1> <ul> <li><a href="http://example.com">Link 1</a></li> <li><a href="http://scrapy.org">Link 2</a></li> </ul </body> </html>""") >>> >>> sel.css('h1::text').extract_first() u'Hello, Parsel!' >>> >>> sel.css('h1::text').re('\w+') [u'Hello', u'Parsel'] >>> >>> for e in sel.css('ul > li'): print(e.xpath('.//a/@href').extract_first()) http://example.com http://scrapy.org
安装方法: pip install parsel
scrapinghub/js2xml(https://github.com/scrapinghub/js2xml)
Convert Javascript code to an XML document
简单来讲就是 将JavaScript代码转换为xml文档。然后可以使用xpath从JavaScript中提取数据,不用写一堆正则了。
>>> import js2xml >>> >>> jscode = """function factorial(n) { ... if (n === 0) { ... return 1; ... } ... return n * factorial(n - 1); ... }""" >>> parsed = js2xml.parse(jscode) >>> >>> parsed.xpath("//funcdecl/@name") # extracts function name ['factorial'] >>> >>> print js2xml.pretty_print(parsed) # pretty-print generated XML <program> <funcdecl name="factorial"> <parameters> <identifier name="n"/> </parameters> <body> <if> <predicate> <binaryoperation operation="==="> <left> <identifier name="n"/> </left> <right> <number value="0"/> </right> </binaryoperation> </predicate> <then> <block> <return> <number value="1"/> </return> </block> </then> </if> <return> <binaryoperation operation="*"> <left> <identifier name="n"/> </left> <right> <functioncall> <function> <identifier name="factorial"/> </function> <arguments> <binaryoperation operation="-"> <left> <identifier name="n"/> </left> <right> <number value="1"/> </right> </binaryoperation> </arguments> </functioncall> </right> </binaryoperation> </return> </body> </funcdecl> </program>
安装方法: `pip install js2xml`
我们先打开美女花瓣,陪你做生活的设计师(发现、采集你喜欢的美女图片)花瓣网(http://huaban.com/favorite/beauty/)
如果我们想把这里面所有美女照片抓取下来的话,那么我们的操作步骤应该是这样的
1.打开首页的每一个”相框”,然后点进去
2.获取所有图片的链接,然后下载下来
用程序实现的话,也是挺简单的
//a[@class=”img x layer-view loaded”]/@href
import requests
from parsel import Selector
url = ‘http://huaban.com/favorite/beauty/‘
headers = {‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36’}
z = requests.get(url,headers=headers)
print z.status_code
#返回200
#使用parsel中的Selector 来解析
sel = Selector(text=z.text)
print sel.xpath(‘//a[@class=”img x layer-view loaded”]/@href’)
#发现返回为空
这边为什么会返回空呢?不是应该返回所有链接的么?
我们可以查看下网页源代码,可以发现的内容都是通过js渲染上去的,所以我们才获取不到内容(这个可以用js2xml来解析,先放在这里,到详情页再来处理。)
j0ga0has:
max:1062527343
limit:20
wfl:1
url = ‘http://huaban.com/favorite/beauty/‘
params = { ‘j0ga0hbi’:’’, ‘max’:’1062161596’, ‘limit’:’100’, ‘wfl’:’1’}
z1 = requests.get(url=url,params=params,headers=headers)
print z1.status_code
#返回200
print z1.json()
#报错
然后发现竟然报错了。。。
为什么呢?我们查看请求的时候就是jsno格式的啊
我们打印下源代码看看
你会看到竟然是”<!DOCTYPE html><html “这样的,但是我们上面查看请求的时候,明明是如下图这样的啊
那么到底是哪里出了问题呢?
我们再次查看之前我们看到的异步请求
可以发现它有几个 特别的请求头
指定了格式为json ,那么我们加上去看看呢
Accept:application/json
X-Request:JSON
X-Requested-With:XMLHttpRequest
headers1 = { ‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36’, ‘Accept’:’application/json’, ‘X-Request’:’JSON’, ‘X-Requested-With’:’XMLHttpRequest’ }
z2 = requests.get(url=url,params=params,headers=headers1)
print z2.content
可以看到返回值和我们之前一样了。
获取pin_id
最后只要把pin_id拼接成url就可以了,如果你想要爬取所有的图片的话,那么你只需要把最后的pin_id 传入给max,再请求一次,直到pins为空为止
在上面我们已经获取到了所有的详情页的地址,那么我们现在只要获取到图片链接就行
就这样,我们已经把图片地址获取到了,只需要拼接下即可(记得去下重)
看完本篇文章后,你应该要
最后代码都在 kimg1234/pachong(https://github.com/kimg1234/pachong/blob/master/huaban%E7%88%AC%E8%99%AB.ipynb)
填一个坑,我在https://mp.weixin.qq.com/s?__biz=MzU2OTAxNTcwMw==&mid=100000023&idx=1&sn=0c0ff48e9bfca19dca6c4ed5bad46e0a&chksm=7c846def4bf3e4f9bde83bc8aa966419022c86dea5db9a00918f3b0220f9432c38f3b991d44a#rd
留下以下问题
其实解决方法也挺简单的,就是把content-type这一行注释掉。
那么为什么注释掉就可以了呢?请仔细研究研究http协议。。。