爬虫文档

一、爬虫原理

1、http协议

超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。

2、http请求

[外链图片转存失败(img-4zvoifu2-1567686176832)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1565832939762.png)]

3、相应状态码

http状态返回代码 2xx (成功)
200   (成功)  服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201   (已创建)  请求成功并且服务器创建了新的资源。
202   (已接受)  服务器已接受请求,但尚未处理。
203   (非授权信息)  服务器已成功处理了请求,但返回的信息可能来自另一来源。
204   (无内容)  服务器成功处理了请求,但没有返回任何内容。
205   (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206   (部分内容)  服务器成功处理了部分 GET 请求。
http状态返回代码 3xx (重定向)
300   (多种选择)  针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301   (永久移动)  请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302   (临时移动)  服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303   (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。

304   (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305   (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307   (临时重定向)  服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
http状态返回代码 4xx(请求错误)
400   (错误请求) 服务器不理解请求的语法。
401   (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403   (禁止) 服务器拒绝请求。
404   (未找到) 服务器找不到请求的网页。
405   (方法禁用) 禁用请求中指定的方法。
406   (不接受) 无法使用请求的内容特性响应请求的网页。
407   (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408   (请求超时)  服务器等候请求时发生超时。
409   (冲突)  服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410   (已删除)  如果请求的资源已永久删除,服务器就会返回此响应。
411   (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412   (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413   (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414   (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415   (不支持的媒体类型) 请求的格式不受请求页面的支持。
416   (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417   (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
http状态返回代码 5xx(服务器错误)
500   (服务器内部错误)  服务器遇到错误,无法完成请求。
501   (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502   (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503   (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504   (网关超时)  服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505   (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。 

4、Cookie Session

cookie:的内容主要包括:名字,值,过期时间,路径和域。**路径与域一起构成 cookie

的作用范围。若不设置过期时间,则表示这个 cookie 的生命期为浏览器会话期间,关闭浏

览器窗口,cookie 就消失。这种生命期为浏览器会话期的 cookie 被称为会话 cookie。

会话 cookie 一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。

若设置了过期时间,浏览器就会把 cookie****保存到硬盘上,关闭后再次打开浏览器,这些 cookie

仍然有效直到超过设定的过期时间

**2、cookie **和session的区别:

1)、cookie 数据存放在客户的浏览器上,session 数据放在服务器上。

2)、cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗, 考虑到安全应当使用 session。

3)、session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用 COOKIE。

4)、单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。

请求头

http://www.useragentstring.com/pages/useragentstring.php?typ=Browser

二、requests模块

1、requestsm请求方法

requests.request():构造一个请求,支撑一下各方法的基础方法

requests.get():获取HTML网页的主要方法,对应HTTP的GET

requests.head():获取HTML网页头的信息方法,对应HTTP的HEAD

requests.post():向HTML网页提交POST请求方法,对应HTTP的POST

requests.put():向HTML网页提交PUT请求的方法,对应HTTP的RUT

requests.patch():向HTML网页提交局部修改请求,对应于HTTP的PATCH

requests.delete():向HTML页面提交删除请求,对应HTTP的DELETE

2、requests的13个参数

data:字典,字节序列或文件对象,作为Request的内容

data={'wd':'123'}

json:JSON格式的数据,作为Request的内容

headers:字典,HTTP定制头(模拟浏览器进行访问)

headers = {'user-agent': 'my-app/0.0.1'}

cokies:字典或CpplieJar,Request中的cookie

auth:元祖,支持HTTP认证功能

files:字典类型,传输文件

multiple_files = [
        ('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
        ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]

timeout:设定超时时间,秒为单位

requests.get('http://github.com', timeout=0.001)

proxies:字典类型,设定访问代理服务器,可以增加登陆认证

proxies = {
  "http": "http://10.10.1.10:3128",
  "https": "http://10.10.1.10:1080",
}

allow_redirects:True//False,默认为True,重定向开关

stream:True/False,默认为True,获取内容立即下载开关

verify:True/False,默认为True,认证SSL证书开关

cert:本地SSL证书路径"""

requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))

3、requests的对象

s = requests.Session()
#初始化cookie
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
#发送请求
r = s.get("http://httpbin.org/cookies")
#打印
print(r.text)

1.请求与相应

#发送请求
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
#获取请求头
r.headers
#获取连接状态
r.status_code
#获取cookies
r.cookies
#打印网页源代码
r.text
#设置编码格式
r.encoding
#获取网页编码
r.apparent_encoding
#下载
r.content
#JSON 响应内容
r.json
#自定义错误
r.raise_for_status()
#重定向
r.url

三、xpath的使用

1、xpath模块

模块的安装

pip install lxml

模块的导入

from lxml import etree

[外链图片转存失败(img-5XtEYEAg-1567686176834)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1561990509535.png)]

[外链图片转存失败(img-9LUX3qhr-1567686176835)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1561990533278.png)]

谓语

[外链图片转存失败(img-8i48DzAN-1567686176835)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1561990564431.png)]

2、xpath使用代码

html = etree.HTML(wb_data)
html_data = html.xpath('/html/body/div/ul/li/a')

打开HTML文件

html = etree.parse('test.html')
html_data = html.xpath('//*')<br>#打印是一个列表,需要遍历
print(html_data)

3、JSON模块

json 模块提供了四个功能:dumps、dump、loads、load,用于字符串 和 python 数据类

1.loads字符串转列表

a = '[1,2,3,4,5]'
print(json.loads(a))
print(type(json.loads(a)))

运行结果

[1, 1, 2, 3, 4, 5]
<class 'list'>

写入文件

a = {"name":"Tom", "age":23}
with open("test.json", "w", encoding='utf-8') as f:
    # indent 超级好用,格式化保存字典,默认为None,小于0为零个空格
    f.write(json.dumps(a, indent=4))
    # json.dump(a,f,indent=4)   # 和上面的效果一样

2、dumps元组转字符串

b = (1, 1, 2, 3, 4, 5)
print(type(json.dumps(b)))
结果:[1, 1, 2, 3, 4, 5]<class 'str'>

3、json.dump()–写到文件

def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True,
        allow_nan=True, cls=None, indent=None, separators=None,
        default=None, sort_keys=False, **kw):

4、load写到内存

def load(fp, *, cls=None, object_hook=None, parse_float=None,
        parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):

[外链图片转存失败(img-viTw2dub-1567686176836)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1562035871232.png)]

四、bs4css选择器Beautiful Soup

1、Beautiful Soup字符串转为lxml

from bs4 import BeautifulSoup
#可以是文件
soup = BeautifulSoup(open("index.html"))
#可以是字符串
soup = BeautifulSoup("<html>data</html>")
soup = BeautifulSoup(html_doc, 'lxml')
soup = BeautifulSoup(html_doc, 'html.parser')

2、模块的导入

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
#几个简单的浏览结构化数据的方法
soup.title
获取
soup.title.name
soup.title.string
soup.title.parent.name
soup.p
soup.p['class']
soup.a
soup.find_all('a')
soup.find(id="link3")

3、对象的种类

1)Tag

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
type(tag)
# <class 'bs4.element.Tag'>

2)name

每个tag都有自己的名字,通过 .name 来获取:

tag.name = "blockquote"
tag
# <blockquote class="boldest">Extremely bold</blockquote>
如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档:
tag.name = "blockquote"
tag
# <blockquote class="boldest">Extremely bold</blockquote>

3)Attributes

一个tag可能有很多个属性. tag <b class="boldest"> 有一个 “class” 的属性,值为 “boldest” . tag的属性的操作方法与字典相同:

tag['class']
# u'boldest'

也可以直接”点”取属性, 比如: .attrs :

tag.attrs
# {u'class': u'boldest'}

tag的属性可以被添加,删除或修改. 再说一次, tag的属性操作方法与字典一样

tag['class'] = 'verybold'
tag['id'] = 1
tag
# <blockquote class="verybold" id="1">Extremely bold</blockquote>

del tag['class']
del tag['id']
tag
# <blockquote>Extremely bold</blockquote>

tag['class']
# KeyError: 'class'
print(tag.get('class'))
# None

4 ) 多值属性

css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
# ["body", "strikeout"]

css_soup = BeautifulSoup('<p class="body"></p>')
css_soup.p['class']
# ["body"]

4、find_all详解

1)name参数

字符串

soup.find_all('b')

正则表达式

soup.find_all(re.compile("^b")

标签列表

soup.find_all(["a", "b"])

True可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点

soup.find_all(True)

参数可以是方法

def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')
soup.find_all(has_class_but_no_id)
# [<p class="title"><b>The Dormouse's story</b></p>,
#  <p class="story">Once upon a time there were...</p>,
#  <p class="story">...</p>]

find_all() 方法搜索当前tag的所有tag子节点

soup.find_all("title")
# [<title>The Dormouse's story</title>]

soup.find_all("p", "title")
# [<p class="title"><b>The Dormouse's story</b></p>]

soup.find_all("a")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

soup.find_all(id="link2")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

import re
soup.find(string=re.compile("sisters"))
# u'Once upon a time there were three little sisters; and their names were\n'

2)keyword参数

#按照id
soup.find_all(id='link2')
soup.find_all(href=re.compile("elsie"))
soup.find_all(id=True)
#多个参数
soup.find_all(href=re.compile("elsie"), id='link1')
#按CSS搜索
soup.find_all("a", class_="sister")

3)string参数

soup.find_all(string="Elsie")
# [u'Elsie']

soup.find_all(string=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']

soup.find_all(string=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story"]

def is_the_only_string_within_a_tag(s):
    ""Return True if this string is the only child of its parent tag.""
    return (s == s.parent.string)

soup.find_all(string=is_the_only_string_within_a_tag)
# [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']

4)limit 参数

soup.find_all("a", limit=2)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

5)recursive 参数

会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数recursive=False

soup.html.find_all("title")
# [<title>The Dormouse's story</title>]

soup.html.find_all("title", recursive=False)
# []

5、其他的查找

1)find_parents() 和 find_parent()用来搜索当前节点的父辈节点

find_parents() 只查找一个

find_parent()查找所有的

a_string.find_parents("a")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

a_string.find_parent("p")
# <p class="story">Once upon a time there were three little sisters; and their names were
#  <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
#  and they lived at the bottom of a well.</p>

a_string.find_parents("p", class="title")

2)find_next_siblings() 和 find_next_sibling()

`find_next_siblings()` 方法返回所有符合条件的后面的兄弟节点, `find_next_sibling()`只返回符合条件的后面的第一个tag节点.

3)find_previous_siblings() 和 find_previous_sibling()

find_previous_siblings() 方法返回所有符合条件的前面的兄弟节点, find_previous_sibling() 方法返回第一个符合条件的前面的兄弟节点:

4)find_all_next() 和 find_next()

find_all_next() 方法返回所有符合条件的节点, find_next() 方法返回第一个符合条件的节点

5)find_all_previous() 和 find_previous()

find_all_previous( name , attrs , recursive , string , **kwargs )
find_previous( name , attrs , recursive , string , **kwargs )
find_all_previous() 方法返回所有符合条件的节点, find_previous() 方法返回第一个符合条件的节点.

6、子节点

1).contents 和 .children

.contents 属性可以将tag的子节点以列表的方式输出

.children 生成器,可以对tag的子节点进行循环:

2).descendants

.descendants 属性可以对所有tag的子孙节点进行递归循环

3).string

如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点:

如果一个tag仅有一个子节点,那么这个tag也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同:

head_tag.contents
# [<title>The Dormouse's story</title>]
head_tag.string
# u'The Dormouse's story'

4).strings 和 stripped_strings

如果tag中包含多个字符串 [2] ,可以使用 .strings 来循环获取:

.stripped_strings 可以去除多余空白内容:

5).parent

属性来获取某个元素的父节点

6).next_sibling 和 .previous_sibling

.next_sibling.previous_sibling 属性来查询兄弟节点:

7).next_siblings 和 .previous_siblings

7、总结

.contents 和 .children都是循环子节点.contents以列表 .children` 生成器
.descendants属性可以对所有tag的子孙节点进行递归循环
.stringtag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点
.strings 和 stripped_strings.strings多个字符串 [2] .strings 来循环获取: .stripped_strings` 可以去除多余空白内容:
.parent属性来获取某个元素的父节点
.next_sibling .previous_sibling.next_sibling.previous_sibling` 属性来查询兄弟节点:
.next_siblings 和 .previous_siblings

五、Selenium模块

driver = webdriver.Firefox()
#初始化
driver.get(url)
#发送请求
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
#移动到页面底部
driver.execute_script("window.scrollTo(0, %d)" %(n))
#滑动

1、查找元素方法

driver.find_element_by_id(“passwd-id”)
find_element_by_tag_name
driver.find_element_by_name(“passwd”)
driver.find_element_by_xpath("//input[@id=‘passwd-id’]")
find_element_by_link_text
find_element_by_class_name
find_element_by_css_selector

在文本框输入数据

selement.send_keys()

通过”Keys”类来模式输入方向键

element.send_keys(" and some", Keys.ARROW_DOWN)
element.clear()
#清除文本框

2、填写表格

选择select

from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_name('name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)
#获取所选项
options = select.options

提交

# Assume the button has the ID "submit" :)
driver.find_element_by_id("submit").click()
element.submit()

3、行为链

from selenium.webdriver import ActionChains
action = ActionChains(driver)
#拖放
action.drag_and_drop(element, target)
#移动光标
action.move_to_element()
#点击
action.click()
#输入
action.send_keys_to_element(对象,'内容')
action_chains.perform()
#输出页面源代码
 print(driver.page_source)

窗口移动

driver.switch_to_window("windowName")
#迭代访问
for handle in driver.window_handles:
    driver.switch_to_window(handle)

4、获取元素

#获取元素属性
logo.get_attribute('class')
#获取文本的值
input.text
#获取id
input.id
#获取location
input.location
#获取标签
input.tag_name
#获取大小
input.size

等待

#隐式等待
from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(10)
wait = WebDriverWait(browser, 10)
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
#显示等待
wait = WebDriverWait(browser, 10)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))

浏览器的前进和后退

back()#前进
forward()#后退

5、cookie操作

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'zhaofan'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())

文件上传

定位<input type="file"> 元素并且调用 send_keys()
#方法传入要上传文件的路径,可以 是对于测试脚本的相对路径,也可以是绝对路径

6、取当前窗口的截图

driver.save_screenshot('screenshot.png')

7、执行JavaScript

browser.execute_script

8、PIL模块

im = Image.open("xiao.png")
#打开图片
11位像素,表示黑和白,但是存储的时候每个像素存储为8bit。
L:8位像素,表示黑和白。
P:8位像素,使用调色板映射到其他模式。
RGB:3x8位像素,为真彩色。
RGBA:4x8位像素,有透明通道的真彩色。
CMYK:4x8位像素,颜色分离。
YCbCr:3x8位像素,彩色视频格式。
I:32位整型像素。
F:32位浮点型像素。
PIL也支持一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。
image.convert('L')

六、scrapy框架

1、安装模块

pip install scrapy
#依赖包
pip install pywin32
#lxml版本过高
pip uninstall lxml
pip install lxml==3.8
#解决 Scrapy 安装错误:Microsoft Visual C++ 14.0 is required..
http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 下载 twisted 对应版本的 whl 文件
#创建项目
scrapy startproject tutorial
#运行蜘蛛
scrapy crawl  mingyan2

2、配置文件

#提高并发性
CONCURRENT_REQUESTS = One hundred.
#增加扭曲的IO线程池的最大大小
REACTOR_THREADPOOL_MAXSIZE = 20.
降低log级别
LOG_LEVEL = 'INFO'
禁止cookies
COOKIES_ENABLED = False
禁止重试
RETRY_ENABLED = False
减小下载超时
DOWNLOAD_TIMEOUT = 15
禁止重定向
REDIRECT_ENABLED = False
启用 “Ajax Crawlable Pages” 爬取
AJAXCRAWL_ENABLED = True

3、Spider

name
#定义spider的名字
allowed_domains
#可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware 启用时, 域名不在列表中的URL不会被跟进。
start_urls
#URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。

1、start_requests()

该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取的第一个Request。

def start_requests(self):
    return [scrapy.FormRequest("http://www.example.com/login",
                               formdata={'user': 'john', 'pass': 'secret'},
                               callback=self.logged_in)]

2、make_requests_from_url`(url)

该方法接受一个URL并返回用于爬取的 Request 对象。 该方法在初始化request时被 start_requests() 调用,也被用于转化url为request。

3、parse`(response)

当response没有指定回调函数时,该方法是Scrapy处理下载的response的默认方法。

4、log(message**[, level, component]**)

使用 scrapy.log.msg() 方法记录(log)message。 log中自动带上该spider的 name 属性。

5、allowed_domains

可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware 启用时, 域名不在列表中的URL不会被跟进。

4、CrawlSpider

1、rules

一个包含一个(或多个) Rule 对象的集合(list)。 每个 Rule 对爬取网站的动作定义了特定表现。 Rule对象在下边会介绍。 如果多个rule匹配了相同的链接,则根据他们在本属性中被定义的顺序,第一个会被使用。

2、parse_start_url

当start_url的请求返回时,该方法被调用。 该方法分析最初的返回值并必须返回一个 Item对象或者 一个 Request 对象或者 一个可迭代的包含二者对象。

3、link_extractor` 是一个 Link Extractor 对象。 其定义了如何从爬取到的页面提取链接。

callback 是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中每获取到链接时将会调用该函数。该回调函数接受一个response作为其第一个参数, 并返回一个包含 Item 以及(或) Request 对象(或者这两者的子类)的列表(list)。

cb_kwargs 包含传递给回调函数的参数(keyword argument)的字典。

follow 是一个布尔(boolean)值,指定了根据该规则从response提取的链接是否需要跟进。 如果 callback 为None, follow 默认设置为 True ,否则默认为 False

process_links 是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中获取到链接列表时将会调用该函数。该方法主要用来过滤。

process_request 是一个callable或string(该spider中同名的函数将会被调用)。 该规则提取到每个request时都会调用该函数。该函数必须返回一个request或者None。 (用来过滤request)

import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class MySpider(CrawlSpider):
    name = 'example.com'#爬虫命名
    allowed_domains = ['example.com']#域名
    start_urls = ['http://www.example.com']

    rules = (
        # 提取匹配 'category.php' (但不匹配 'subsection.php') 的链接并跟进链接(没有callback意味着follow默认为True)
        Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),

        # 提取匹配 'item.php' 的链接并使用spider的parse_item方法进行分析
        Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'),
    )

    def parse_item(self, response):
        self.log('Hi, this is an item page! %s' % response.url)
        item = scrapy.Item()
        item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
        item['name'] = response.xpath('//td[@id="item_name"]/text()').extract()
        item['description'] = response.xpath('//td[@id="item_description"]/text()').extract()
        return item

5、item pipeline

1)process_item`(self, item, spider)

#每个item pipeline组件都需要调用该方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。

参数:	
item (Item 对象) – 被爬取的item
spider (Spider 对象) – 爬取该item的spider

2)open_spider`(self, spider)

#当spider被开启时,这个方法被调用。

参数:	spider (Spider 对象) – 被开启的spider

3)close_spider(spider)

#当spider被关闭时,这个方法被调用

#参数:	spider (Spider 对象) – 被关闭的spider

4)from_crawler(cls, crawler)

#如果存在,则调用此类方法从爬虫程序创建管道实例。它必须返回管道的一个新实例。爬虫对象提供访问所有杂乱的核心组件,如设置和信号;这是管道访问它们并将其功能挂钩到Scrapy的一种方法。

5)Item pipeline 样例

from scrapy.exceptions import DropItem

class PricePipeline(object):

    vat_factor = 1.15

    def process_item(self, item, spider):
        if item['price']:
            if item['price_excludes_vat']:
                item['price'] = item['price'] * self.vat_factor
            return item
        else:
            raise DropItem("Missing price in %s" % item)

6)将item写入JSON文件

import json

class JsonWriterPipeline(object):

    def __init__(self):
        self.file = open('items.jl', 'wb')

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item

7、完整的案例

import pymongo

class MongoPipeline(object):

    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def close_spider(self, spider):
        self.client.close()

    def process_item(self, item, spider):
        collection_name = item.__class__.__name__
        self.db[collection_name].insert(dict(item))
        return item

8)去重

from scrapy.exceptions import DropItem

class DuplicatesPipeline(object):

    def __init__(self):
        self.ids_seen = set()

    def process_item(self, item, spider):
        if item['id'] in self.ids_seen:
            raise DropItem("Duplicate item found: %s" % item)
        else:
            self.ids_seen.add(item['id'])
            return item

9)启用一个Item Pipeline组件

ITEM_PIPELINES = {
    'myproject.pipelines.PricePipeline': 300,
    'myproject.pipelines.JsonWriterPipeline': 800,
}

6、启动指令

 >>>redis-cli
 >>>auth 123456   
 >>>lpush mypeople:start_url http://politics.people.com.cn/GB/1024/index1.html

附录:

短视频去水印网站

http://www.kaolajiexi.com/

音乐解析外链

https://link.hhtjim.com/

视频解析网站

腾讯视频,爱奇艺,优酷视频各大视频网站都可以解析……

https://jx.618g.com/?url=   视频解析

如果有跟好的解析网站可以私信

def process_item(self, item, spider):
    collection_name = item.__class__.__name__
    self.db[collection_name].insert(dict(item))
    return item

8)去重

```python
from scrapy.exceptions import DropItem

class DuplicatesPipeline(object):

    def __init__(self):
        self.ids_seen = set()

    def process_item(self, item, spider):
        if item['id'] in self.ids_seen:
            raise DropItem("Duplicate item found: %s" % item)
        else:
            self.ids_seen.add(item['id'])
            return item

9)启用一个Item Pipeline组件

ITEM_PIPELINES = {
    'myproject.pipelines.PricePipeline': 300,
    'myproject.pipelines.JsonWriterPipeline': 800,
}

6、启动指令

 >>>redis-cli
 >>>auth 123456   
 >>>lpush mypeople:start_url http://politics.people.com.cn/GB/1024/index1.html

附录:

短视频去水印网站

http://www.kaolajiexi.com/

音乐解析外链

https://link.hhtjim.com/

视频解析网站

腾讯视频,爱奇艺,优酷视频各大视频网站都可以解析……

https://jx.618g.com/?url=   视频解析

如果有跟好的解析网站可以私信

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
python爬虫与项目实战,网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成。 随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战。搜索引擎(Search Engine),例如传统的通用搜索引擎AltaVista,Yahoo!和Google等,作为一个辅助人们检索信息的工具成为用户访问万维网的入口和指南。但是,这些通用性搜索引擎也存在着一定的局限性,如: (1)不同领域、不同背景的用户往往具有不同的检索目的和需求,通用搜索引擎所返回的结果包含大量用户不关心的网页。 (2)通用搜索引擎的目标是尽可能大的网络覆盖率,有限的搜索引擎服务器资源与无限的网络数据资源之间的矛盾将进一步加深。 (3)万维网数据形式的丰富和网络技术的不断发展,图片、数据库、音频、视频多媒体等不同数据大量出现,通用搜索引擎往往对这些信息含量密集且具有一定结构的数据无能为力,不能很好地发现和获取。 (4)通用搜索引擎大多提供基于关键字的检索,难以支持根据语义信息提出的查询。 网络爬虫 为了解决上述问题,定向抓取相关网页资源的聚焦爬虫应运而生。聚焦爬虫是一个自动下载网页的程序,它根据既定的抓取目标,有选择的访问万维网上的网页与相关的链接,获取所需要的信息。与通用爬虫(general purpose web crawler)不同,聚焦爬虫并不追求大的覆盖,而将目标定为抓取与某一特定主题内容相关的网页,为面向主题的用户查询准备数据资源。 传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。聚焦爬虫的工作流程较为复杂,需要根据一定的网页分析算法过滤与主题无关的链接,保留有用的链接并将其放入等待抓取的URL队列。然后,它将根据一定的搜索策略从队列中选择下一步要抓取的网页URL,并重复上述过程,直到达到系统的某一条件时停止。另外,所有被爬虫抓取的网页将会被系统存贮,进行一定的分析、过滤,并建立索引,以便之后的查询和检索;对于聚焦爬虫来说,这一过程所得到的分析结果还可能对以后的抓取过程给出反馈和指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值