爬虫精进0

第0关

练习-文章下载-参考

题目要求:获取文章[《HTTP状态响应码》]全部内容,并且打印出全文内容。

文本URL:

https://localprod.pandateacher.com/python-manuscript/crawler-html/exercise/HTTP%E5%93%8D%E5%BA%94%E7%8A%B6%E6%80%81%E7%A0%81.md

首先调用requests库,使用requests.get('URL')获取文件,返回的是Response对象。

然后需要把Response对象用合适的数据形式返回。

最后存储数据:

存储文件的三个步骤:打开文件,存储文件,关闭文件。

【提示】

这是一个文本,所以应该使用response.text,把Response对象的内容以字符串的形式返回。

【解答】

选择语言
import requests
destnation_url = 'https://localprod.pandateacher.com/python-manuscript/crawler—html/exercise/HTTP%E5%93%8D%E5%BA%94%E7%8A%B6%E6%80%81%E7%A0%81.md'
res = requests.get (destnation_url)
print(res.status_code) # 查看响应码
article=res.text # 把Response对象的内容以字符串的形式返回
print(article)

练习-图片下载-参考

题目要求:

获取下面的图片,并储存图片。

https://res.pandateacher.com/2019-01-12-15-29-33.png

完成存储后,重新刷新页面,即可在【文件】内看到图片。

【提示】

1. 获取数据

图片URL:https://res.pandateacher.com/2019-01-12-15-29-33.png

首先调用requests库,使用requests.get('URL')获取文件,返回的是Response对象。

然后需要把Response对象用合适的数据形式返回。

2. 存储数据

存储文件的三个步骤:打开文件,存储文件,关闭文件。

这是一个图片,所以应该使用response.content,把Response对象的内容以二进制数据的形式返回。

【解答】

选择语言
import requests
res = requests.get('https://res.pandateacher.com/2019-01-12-15-29-33.png')
# 发出请求,并把返回的结果放在变量res中
pic=res.content
# 把Reponse对象的内容以二进制数据的形式返回
photo = open('spider.jpg','wb')
# 新建了一个文件ppt.jpg,这里的文件没加路径,它会被保存在程序运行的当前目录下。
# 图片内容需要以二进制wb读写。你在学习open()函数时接触过它。
photo.write(pic)
# 获取pic的二进制内容
photo.close()
# 关闭文件

练习-音频下载-参考

题目要求:

获取下面的音乐,并且储存它,然后请刷新页面,这样你就可以在【文件】内看到它。音乐URL:

https://static.pandateacher.com/Over%20The%20Rainbow.mp3

1. 获取数据

音乐URL:https://static.pandateacher.com/Over%20The%20Rainbow.mp3

首先调用requests库,使用requests.get('URL')获取文件,返回的是Response对象。

然后需要把Response对象用合适的数据形式返回。

2. 存储文件

存储文件的三个步骤:打开文件,存储文件,关闭文件。

【提示】

这是一个音频,所以应该使用response.content,把Response对象的内容以以二进制数据的形式返回。

【解答】

选择语言
import requests
res=requests.get('https://static.pandateacher.com/Over%20The%20Rainbow.mp3')
# 发出请求,并把返回的结果放在变量res中
mp3=res.content
# 把Reponse对象的内容以二进制数据的形式返回
music = open('rainbow.mp3','wb')
# 新建了一个文件ppt.jpg,这里的文件没加路径,它会被保存在程序运行的当前目录下。
# 图片内容需要以二进制wb读写。你在学习open()函数时接触过它。
music.write(mp3)
# 获取pic的二进制内容
music.close()
# 关闭文件

第1关

练习-我的书苑我作主-参考

复习了所有知识点,一切都准备就绪,那就开始写属于你的网页吧!

我已经把网页的HTML源代码准备好了,你直接在上面修改就好。

现在,请把网页[这个书院不太冷5.0](https://localprod.pandateacher.com/python-manuscript/crawler-html/spider-men5.0.html)修改为你喜欢的模样。

必做:

- 修改网页标题

- 增加至少一本书的描述

- 修改网页底部

选做:

- 修改已有书籍的描述

- 增加多本书的描述

- 自由地在HTML文档上修改任意内容

【提示】

网页结构修改:

为了让网页的结构更加清晰,可以把每一本书都写成一个`<div>`元素。

细节的修改:

书籍封面图片的URL,你可以试试用豆瓣书籍主页的图片。右键点击图片,然后选择【复制图片地址】(https://res.pandateacher.com/2019-01-12-21-30-00.png)

【解答】

你的书苑你做主。

这是我给你的参考答案,你可以点开下面的链接看看:

https://localprod.pandateacher.com/python-manuscript/crawler-html/exercise/01-01-test.html

⚠️注意,修改图片是直接将自己要替换的图片的链接在检查里面双击替换

另外,有的同学在学习第1关课程的时候,会遇见以下情况:





右边空空如也?遇到这种情况怎么办?莫慌!

在本地文件夹新建一个.txt文件,并把后缀改为.html









然后,鼠标右键点击这个文件,选择“打开方式”,再选择“记事本”





把课堂上的html代码复制粘贴过来,并选择左上角的“文件”,再选择“另存为”;





在另存为里,需要将编码格式修改为“utf-8”哦,然后点击“保存”





最后一步,鼠标双击打开 书苑.html 这个文件,就可以得到一个本地的网页啦





第2关

练习-博客爬虫-参考

题目要求:

你需要爬取的是博客【人人都是蜘蛛侠】中,《未来已来(四)——Python学习进阶图谱》的所有文章评论,并且打印。

文章URL:

https://wordpress-edu-3autumn.localprod.oc.forchange.cn/all-about-the-future_04/

【提示】

首先,记得调用requests库和BeautifulSoup模块

然后,按照爬虫的四个步骤来写代码:(不需要写第3步存储数据)

第0步:获取数据

`requests.get()`

第1步:解析数据

`BeautifulSoup(网页源代码的字符串格式,'html.parser')`

第2步:提取数据

`find_all()`

`for`循环遍历`list`

`Tag.text`

第2关-爬取蜘蛛侠网评论

https://wordpress-edu-3autumn.localprod.oc.forchange.cn/all-about-the-future_04/

打开网站,将页面拉到下面的评论区域





没错,我们要爬取的就是这些评论,最重要的就是能够十分精准地定位到评论所在的标签

跟着助教操作吧,选择一条评论,鼠标右键,点击“检查”





此时检查会打开,并在element里定位到该评论所在的标签下,如图





恭喜你,迅速又准确地找到了这个标签的位置,接下来我们需要检查一下,定位到这个标签的话,能否准确的提取出数据?

首先是评论所在的<p>标签。让我们在element里面 ctrl+F ,调出搜索框,直接搜'p’





emmmmm,266个?算了算了(如果你有经验的话,是可以直接判断出p标签定位是肯定行不通的)

那我们往上找一级,<p>标签再上一级是?是 <div' class= 'comment-content'>

来,再搜一搜'comment-content’





嗯哼,搜出来6个,而且仔细观察一下,每一个<div' class= 'comment-content'> 都包含一个评论的内容。没错,这就是我们要找的!

ok,现在应该有个思路了,定位到这个标签,并且提取出标签下的文本内容

我们可以用 .find_all('div',class_= 'comment-content') 定位标签

为什么用find_all(),因为每个评论都是一个独立的标签,而我们需要把所有标签都抓下来,所以要用到find_all()

那要注意的是,find_all()得到的是一个列表,所以find_all()后面是不能直接加.text的哦!

我们需要用到列表循环遍历的方式,把每一个Tag对象先从列表里拿出来,再加上.text提取文本内容

答案是这样的:

选择语言
import requests # 调用requests库
from bs4 import BeautifulSoup # 调用BeautifulSoup库
destnation_url = 'https://wordpress-edu-3autumn.localprod.oc.forchange.cn/all-about-the-future_04/comment-page-545/#comments'
# 把网址复制给变量destnation_url
destnation = requests.get (destnation_url) # 返回一个response对象,赋值给destnation
soup = BeautifulSoup(destnation.text,'html.parser') # 把网页解析为BeautifulSoup对象
comments = soup.find_all('div',class_= 'comment-content') #通过匹配属性提取出我们想要的元素
for comment in comments: # 遍历列表,取出列表中的每一个值
print(comment.text) # 打印评论的文本

同学应该发现,这个代码只能爬取到最后一页的评论内容

别着急嘛,那这个网址只能爬取当前页的内容,那我们看看其他页有没有什么特点呢?

第545页:

https://wordpress-edu-3autumn.localprod.oc.forchange.cn/all-about-the-future_04/comment-page-545/#comments

第544页:

https://wordpress-edu-3autumn.localprod.oc.forchange.cn/all-about-the-future_04/comment-page-544/#comments

第543页:

https://wordpress-edu-3autumn.localprod.oc.forchange.cn/all-about-the-future_04/comment-page-543/#comments

看出来了嘛?变化就是数字。思考一下,如何利用这个数字去实现不同页码的改变?

如果我们假设这个数字是一个变量 x ,那有什么方法可以让这个 x 实现叠加变化

想到了嘛?用 循环

这里以for循环作为一个例子,要注意url的数据拼接部分哦!

选择语言
import requests # 调用requests库
from bs4 import BeautifulSoup # 调用BeautifulSoup库
for x in range(1,545):
    destnation_url = 'https://wordpress-edu-3autumn.localprod.oc.forchange.cn/all-about-the-future_04/comment-page-'+str(x)+'/#comments'
    # 把网址复制给变量destnation_url
    destnation = requests.get (destnation_url) # 返回一个response对象,赋值给destnation
    soup = BeautifulSoup(destnation.text,'html.parser') # 把网页解析为BeautifulSoup对象
    comments = soup.find_all('div',class_= 'comment-content') #通过匹配属性提取出我们想要的元素
    for comment in comments: # 遍历列表,取出列表中的每一个值
        print(comment.text) # 打印评论的文本

练习-书店寻宝-参考

1.第一个小练习

题目要求:你需要爬取的是网上书店(http://books.toscrape.com/)中所有书的分类类型,并且将它们打印出来。网页URL:http://books.toscrape.com/

【提示】

要找到就需要先找到所有的li标签,仔细看HTML源代码的结构,这里需要嵌套提取好几层:

`find('ul',class_='nav').find('ul').find_all('li')`

最终打印结果,可以使用`str.strip()`去除特殊字符串。

比如,使用`.strip()`即可去掉'   我是吴枫\n'文字前面的空格与后面的换行。

http://books.toscrape.com/

第一个小练习,我们要把这网站左侧的各种书籍的分类给提取出来

来,开始。第一步,最便捷的方式,右键点击第一个分类“Travel”,然后选择“检查”





检查会被打开,并且自动定位到element里面的标签位置





简单看一下右边的标签情况,很多<li>标签中,打开的是第一个<li>标签

<li>标签下又是一个<a>标签,那我们把这个<a>标签展开看一看





嗯,没错。Travel这个分类的文本内容就在这个标签下。接着我们继续多看一下几个<li>标签,会发现,每个<li>标签下都是一个分类的文本





那大概的思路是不是有啦?

同学可能会这么想:定位到<li>标签,爬它!

等等等等,别着急

真的以为定位到<li>标签就好了?

再检查一下吧,用ctrl+F搜索一下<li>标签

结果如下





搜出来的第一个<li>标签,不是我们需要的内容。这说明,如果直接定位到<li>标签是不准确的

所以我们还是一步步来定位,不用要求一步到位哦





这里需要提取好几层呢,耐心一点,精准一点

最后,我们可以把程序写出这个样子

选择语言
import requests
from bs4 import BeautifulSoup
res_bookstore = requests.get('http://books.toscrape.com/')
bs_bookstore = BeautifulSoup(res_bookstore.text,'html.parser')
list_kind = bs_bookstore.find('ul',class_='nav').find('ul').find_all('li') # 这里需要提取好几层
for tag_kind in list_kind:
    tag_name = tag_kind.find('a')
    print(tag_name.text.strip()) # 去除特殊字符串,比如空格,\n,\t等等

这里有三处需要注意:

1、第7行,这里是把所有的标签定位连写,同学们在自己练习的时候,可以分开一步步来写;

2、第7行,最后用的find_all('li’)是把所有<li>标签爬取下来,得到的是一个列表;

3、第12行,tag_name.text是提取出<a>标签的文本部分,.strip() 是将文本部分的特殊字符切除,同学们在练习的时候,可以把这个去掉和加上,看看两者的区别是什么;

2.第二个小练习

题目要求:你需要爬取的是网上书店[Books to Scrape](http://books.toscrape.com/)Travel这类书中,所有书的书名、评分、价格三种信息,并且打印提取到的信息。

网页URL:http://books.toscrape.com/catalogue/category/books/travel_2/index.html

在此,提取书名和评分都有一定难度,想不到怎么做?查看提示。

【提示】

1.提取书名:

需要注意的是,`<a>`标签中的文字内容所显示的不是完整书名,完整的书名是`<a>`标签中,`<title>`属性的值。

因此需要用到`tag['属性名']`来提取属性值。

2.提取评分:

需要注意的是,评分藏在了`<p>`标签的`<class>`属性中,它是`<class>`的第1个属性值。

我们需要根据`<class>`的第0个属性值`<star-rating>`提出它的第1个属性值。

http://books.toscrape.com/

题目要求我们爬取Travel类别下,所有书籍的信息。首先我们可以先看一下,每本书的信息是否有独立的标签包含着,这里,我们找到的一个标签是 <article class='product_pod'>

我们从左边的蓝色阴影也可以看出,这个标签下包含了该本书籍的所有信息,那就是它了,我们需要先把标签定位到这里来





选择语言
import requests
from bs4 import BeautifulSoup
res_bookstore = requests.get('http://books.toscrape.com/catalogue/category/books/travel_2/index.html')
bs_bookstore = BeautifulSoup(res_bookstore.text,'html.parser')
list_books = bs_bookstore.find_all(class_='product_pod')

注意,这里用的是find_all(),是要把每本书都先独立提取出来。接下来,我们再进入每一个<article class='product_pod'>下进行数据的提取

书名提取

可以跟着上一步的标签定位,继续把下面的标签展开看看有什么内容

找到是在<article>标签下的<h3>标签下的<a>标签,这里要提取2层才能找到书名的文本内容哦





仔细观察一下,如果这里提取文本的话,后面是个“...”的省略号,而不是完整的书名信息

那,再仔细观察一下,<a>标签中有一个“title”属性,而这个属性的内容却是完整的书名

ok,既然这样,我们就不提取文本内容了,改为提取<a>标签的“title”属性

还记得怎么提取标签的属性嘛?用的是Tag['属性名']的格式,来看看代码

选择语言
import requests
from bs4 import BeautifulSoup
res_bookstore = requests.get('http://books.toscrape.com/catalogue/category/books/travel_2/index.html')
bs_bookstore = BeautifulSoup(res_bookstore.text,'html.parser')
list_books = bs_bookstore.find_all(class_='product_pod')
for tag_books in list_books:
    tag_name = tag_books.find('h3').find('a') # 找到a标签需要提取两次
    print(tag_name['title']) # 这里用到了tag['属性名']提取属性值

ok?ok就继续往下,不ok就多看多操作几遍

评分提取

这里重点讲一下评分的提取。首先我们先定位下整个评分的标签是什么。可以用到我们的小箭头工具,然后移到评分的位置,在element会自动定位到标签





这本书有三颗星星,看看左边的标签,<p class='star-rating Three'>,刚好是Three。

再多看几本书后,基本上就可以确定这个标签就是我们要提取的书籍评分内容

这里需要注意了,我们的目的是要提取<p>标签的class属性的值

而这里,class属性是有两个值的,分别是star-rating和Three,中间用空格分开

定位标签时,为了定位准确,我们可以定位所有书都有的<p>标签的class属性:“star-rating”

然后用Tag['属性名']的格式提取出class属性的值。而因为上面说了,class属性是有两个值的,所以返回的是一个列表。我们需要提取的是列表中偏移量为1的值,所以还需要加上[1]来提取

完整写出来是这样滴:

选择语言
import requests
from bs4 import BeautifulSoup
res_bookstore = requests.get('http://books.toscrape.com/catalogue/category/books/travel_2/index.html')
bs_bookstore = BeautifulSoup(res_bookstore.text,'html.parser')
list_books = bs_bookstore.find_all(class_='product_pod')
for tag_books in list_books:
    list_star = tag_books.find('p',class_='star-rating')
    # 这个p标签的class属性有两种:'star-rating',以及具体的几星比如'Two'。我们选择所有书都有的class属性:'star-rating'
    print('star-rating:',list_star['class'][1])

ok?ok就继续往下,不ok就多看多操作几遍

价格提取

价格这个书籍的信息是比较简单的,同样可以借助小箭头的工具,帮助我们快速地定位找这个标签

结果出来了,是<p class='price_color'>这个标签,而价格的信息是该标签的文本内容

思路出来了不?定位到该标签,再提取出文本内容

怎么提取文本内容?用Tag.text的格式





选择语言
import requests
from bs4 import BeautifulSoup
res_bookstore = requests.get('http://books.toscrape.com/catalogue/category/books/travel_2/index.html')
bs_bookstore = BeautifulSoup(res_bookstore.text,'html.parser')
list_books = bs_bookstore.find_all(class_='product_pod')
for tag_books in list_books:
    tag_price = tag_books.find('p',class_='price_color') # 价格比较好找,根据属性提取,或者标签与属性一起都可以
    print('Price:',tag_price.text, end='\n'+'------'+'\n') # 打印的时候,我加上了换行,为了让数据更加清晰地分隔开,当然你也可以不加。

这样,我们就分别完成了书名、评分、价格三个书籍信息的提取了

当然,最后我们还需要把这三部分的内容整合一下,完整的代码,自己尝试写写看吧!

练习-博客文章-参考

题目要求:你需要爬取的是博客(https://wordpress-edu-3autumn.localprod.forc.work/),首页的四篇文章信息,并且打印提取到的信息。

提取每篇文章的:

- 文章标题

- 发布时间

- 文章链接

网页URL:https://spidermen.cn/

【提示】

文章题目与URL的提取方式稍有不同:

``` html

<h2 class='entry-title'>

<a href='https://wordpress-edu-3autumn.localprod.forc.work/all-about-the-future_04/' rel='bookmark'>未来已来(四)——Python学习进阶图谱</a>

</h2>

```

文章标题可以通过`<h2>`与`<class_='entry-title'>`找到,并用`Tag.text`提取出。

而文章URL必须定位到`<a>`元素才可以。

【解答】

选择语言
import requests
from bs4 import BeautifulSoup
url_destnation = 'https://spidermen.cn/'
res_destnation = requests.get (url_destnation)
print(res_destnation.status_code) # 打印响应码
bs_articles = BeautifulSoup(res_destnation.text,'html.parser')
list_articles = bs_articles.find_all('header', class_ = 'entry-header') # 首先找到每篇文章所在的相同的元素
for tag_article in list_articles: # 遍历列表
    tag_title = tag_article.find('h2',class_ = 'entry-title') # 找文章标题
    tag_url = tag_article.find('a',rel = 'bookmark')  # 找文章链接
    tag_date = tag_article.find('time',class_='entry-date published') # 找文章发布时间
    print(tag_title.text,'发布于:',tag_date.text) # 打印文章标题与发布时间
    print(tag_url['href'])  # 换行打印文章链接,需要使用属性名提取属性值

第3关

练习-豆瓣爬虫-参考

第一步:分析问题,明确结果

问题需求就是把豆瓣TOP250里面的 序号/电影名/评分/推荐语/链接 都爬取下来,结果就是全部展示打印出来

【讲解】

问题需求就是把豆瓣TOP250里面的 序号/电影名/评分/推荐语/链接 都爬取下来,结果就是全部展示打印出来

第二步:思考要用到的知识

要爬取“序号/电影名/评分/推荐语/链接”这些信息,我们已经学习了用requests.get()获取数据,BeautifulSoup库解析数据,find()和find_all()提取数据,还有呢,观察下,一共10页,我们还要加个for循环对吧~

https://shimo.im/docs/QWQJYGw8CtcwQwyq/ 《豆瓣250爬虫思路详解》

豆瓣电影爬取思路1

首先要提醒同学,因为我们课堂上练习的同学太多啦,所以现在豆瓣会对我们的ip进行反爬的限制。通常报错为NoneType Error,这种情况下,同学可以在本地编辑器运行没问题就ok,课程的空代码运行跳过哦

思路1的方法是:先爬取最小共同父级标签 `<li>`,然后针对每一个父级标签,提取里面的序号/电影名/评分/推荐语/链接。

先看看代码吧:

选择语言
import requests, random, bs4
for x in range(10):
headers = {
'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
# 标记了请求从什么设备,什么浏览器上发出
}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
bs = bs4.BeautifulSoup(res.text, 'html.parser')
bs = bs.find('ol', class_='grid_view')
for titles in bs.find_all('li'):
num = titles.find('em',class_='').text
#查找序号
title = titles.find('span', class_='title').text
#查找电影名
tes = titles.find('span',class_='inq').text
#查找推荐语
comment = titles.find('span',class_='rating_num').text
#查找评分
url_movie = titles.find('a')['href']
print(num + '.' + title + '——' + comment + '\n' + '推荐语:' + tes +'\n' + url_movie)

看着我们需要的信息一条条蹦出来,还是很兴奋的哈哈哈

到144条怎么停下来报错了,哎?不要慌





那我们看看报错信息是啥呢:AttributeError: 'NoneType' object has no attribute 'text'

意思是:爬取到NoneType的数据不能直接使用.text

为什么会有NoneType呢?是在执行这一句tes = titles.find('span',class_='inq').text的时候报错了

再看到上面,是爬取到144这个电影时候停下来的,那我们找到这个电影吧!





这就是问题所在,144这部电影没有推荐语,而空值是没办法做text文本转换的,因此报错了呢

那怎么解决呢,聪明的你一定想到啦,加一个判断就可以啦!

判断电影是否有推荐语,有的话则打印,没有则不打印

修改过代码,我们再试一下哦

选择语言
import requests, random, bs4
for x in range(10):
headers = {
'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
# 标记了请求从什么设备,什么浏览器上发出
}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
bs = bs4.BeautifulSoup(res.text, 'html.parser')
bs = bs.find('ol', class_='grid_view')
for titles in bs.find_all('li'):
num = titles.find('em',class_='').text
title = titles.find('span', class_='title').text
comment = titles.find('span',class_='rating_num').text
url_movie = titles.find('a')['href']
if titles.find('span',class_='inq') != None:
tes = titles.find('span',class_='inq').text
print(num + '.' + title + '——' + comment + '\n' + '推荐语:' + tes +'\n' + url_movie)
else:
print(num + '.' + title + '——' + comment + '\n' +'\n' + url_movie)

好啦,250个电影的信息都抓取到了耶!

到这里其实我们已经完成了抓取,但是再思考一下,除了加if判断之外,还有没有学过相关的debug知识可以使用起来呢?

在基础语法我们曾学道try...except...的方法,不知道大家还有没有印象呢?

我们可以试一下,正常情况下,用try打印出所有电影的信息;而当遇到报错的时候,执行到except,不打印电影推荐语这一项信息

再来看看代码吧:

选择语言
import requests, random, bs4
for x in range(10):
headers = {
'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
# 标记了请求从什么设备,什么浏览器上发出
}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
    bs = bs4.BeautifulSoup(res.text, 'html.parser')
    bs = bs.find('ol', class_='grid_view')
    for titles in bs.find_all('li'):
        try:
            num = titles.find('em',class_='').text
            #查找序号
            title = titles.find('span', class_='title').text
            #查找电影名
            tes = titles.find('span',class_='inq').text
            #查找推荐语
            comment = titles.find('span',class_='rating_num').text
            #查找评分
            url_movie = titles.find('a')['href']         
            print(num + '.' + title + '——' + comment + '\n' + '推荐语:' + tes +'\n' + url_movie)
        except:
            print(num + '.' + title + '——' + comment + '\n' + '推荐语:无' +'\n' + url_movie)

以上就是两种处理报错的方式,同学们多消化一下哦!

豆瓣电影爬取思路2

首先要提醒同学,因为我们课堂上练习的同学太多啦,所以现在豆瓣会对我们的ip进行反爬的限制。通常报错为NoneType Error,这种情况下,同学可以在本地编辑器运行没问题就ok,课程的空代码运行跳过哦

思路2的方法是:分别提取所有的序号/所有的电影名/所有的评分/所有的推荐语/所有的链接,然后再按顺序一一对应起来。

一个个找吧,有点多,有点复杂,但是不怕它!每每去研究一个网站都是要花不少时间的,但学习不怕花时间哦。来吧!

1、电影序号的标签定位





2、电影名的标签定位





3、电影链接的标签定位





我们可以借助小箭头工具,快速定位到相关的标签,并通过展开右边的各个标签后,大概找到我们需要的内容。

到这一步,同学可能会着手尝试,把每个数据对于的标签都单独的find_all()一遍

尝试一下是可以的,但是这里咱们仔细观察一下,上面的三种数据,是不是都包含在<div class='item'>这个标签下呢?





对吧?那我们可以三合一,先直接定位到<div class='item'>,后面再去进行这个标签下面的数据提取。

继续往下吧,还需要提取评分和推荐语

4、电影评分的标签定位





5、电影推荐语的标签定位





好,现在我们大概找到了所有相关信息的标签了

那我们再来理一理思路:

我们要爬取10页的内容,每一页用find_all()的方法去爬取标签,然后再通过遍历的方法,按顺序把需要的内容从find_all()得到的列表里提取出来做处理,再分别写入一个大的列表...

差不多就是这样,那来写写代码吧

选择语言
import requests
# 引用requests模块
from bs4 import BeautifulSoup
for x in range(10):
headers = {
'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
# 标记了请求从什么设备,什么浏览器上发出
}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
    bs = BeautifulSoup(res.text, 'html.parser')
    tag_num = bs.find_all('div', class_='item')
    # 查找包含序号,电影名,链接的<div>标签
    tag_comment = bs.find_all('div', class_='star')
    # 查找包含评分的<div>标签
    tag_word = bs.find_all('span', class_='inq')
    # 查找推荐语
    list_all = []
    for x in range(len(tag_num)):
        list_movie = [tag_num[x].text[2:5], tag_num[x].find('img')['alt'], tag_comment[x].text[2:5], tag_word[x].text, tag_num[x].find('a')['href']]
        list_all.append(list_movie)
    print(list_all)

运行了一下,阿喔,报错了?

是不是第一反应就是想来找助教说:“助教你这个错啦!”

是的是的,上面这个报错了,那我们看看报错信息是啥呢:IndexError: list index out of range ,意思是:列表的索引超出了范围

那上面有这么多个索引的内容,我们需要去排查到底是哪一个索引出了问题

有两种方式:

方式1,把每个索引单独打印一遍,逐一排查;

方式2,看看已经打印的信息,是打印到哪个阶段才停下来的?然后根据已打印的情况去定位问题;

比如,助教在写这个文档的时候,运行这个程序,是在第176个电影的时候停下来的,如下图





那我们到网页上去找找这个电影吧,看看是出了什么小bug

哦豁,第143个电影信息没问题,但是第144个电影信息却是没有“推荐语”这一项的

这就是问题所在,没有推荐语,但是没有写入列表,所以会导致在索引的时候发生偏移量溢出的情况,所以报错了





行了,出了问题,我们就来想办法解决

既然有一部电影是没有推荐语的,那还会不会有其他电影也是没有推荐语的呢?

可能有,也可能没有。因为这个网页的信息是会在变化的,助教在写这个文档的时候,是找到了一共3个电影没有推荐语,除了上面的《绿皮书》,还有下面两部,序号分别是“144”、“208”、“240”、'’241'’、'’246’'

同学们在自己练习的时候,要以实际情况为准

















助教这里直接把处理的思路告诉同学,我们可以用if条件加判断,当电影序号满足上面几个的情况时,补充一个“推荐语”给这部电影,这样就可以避免列表索引溢出的情况了

助教把代码都整理出来了

我们先来直接看一下代码,然后逐行去理解

选择语言
import requests
# 引用requests模块
from bs4 import BeautifulSoup
for x in range(10):
headers = {
'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
# 标记了请求从什么设备,什么浏览器上发出
}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
    bs = BeautifulSoup(res.text, 'html.parser')
    tag_num = bs.find_all('div', class_='item')
    # 查找包含序号,电影名,链接的<div>标签
    tag_comment = bs.find_all('div', class_='star')
    # 查找包含评分的<div>标签
    tag_word = bs.find_all('span', class_='inq')
    # 查找推荐语 
    list_all = []
    for x in range(len(tag_num)):
        if tag_num[x].text[2:5] == '144' or tag_num[x].text[2:5] =='208' or tag_num[x].text[2:5] =='240' or tag_num[x].text[2:5] =='241' or tag_num[x].text[2:5] =='246':
            tag_word.insert(x,'没有推荐语')
            list_movie = [tag_num[x].text[2:5], tag_num[x].find('img')['alt'], tag_comment[x].text[2:5], tag_word[x], tag_num[x].find('a')['href']]
        else:
            list_movie = [tag_num[x].text[2:5], tag_num[x].find('img')['alt'], tag_comment[x].text[2:5], tag_word[x].text, tag_num[x].find('a')['href']]
        list_all.append(list_movie)
    print(list_all)

最后,我当然知道你们还想问什么了

tag_word[x].text[2:5],这个[2:5]怎么来的?

我们先把[2:5]去掉打印看看咯?结果如下(举个列子所以我随意挑了126这部电影)





打印出来的文字信息很多,但是我们只需要126这三个数字

那126前面有两行空格,共占两个字符长度,偏移量为 [0] 和 [1]

而126三个数字,各占一个字符,偏移量分别为[2],[3],[4]

后面无关字符就是[5:]

根据左取右不取原则,我们只要把 [2:5] 这部分保留下来就ok啦

这个练习,重在提供一种解决问题的思路给同学,在实际运用中,并不是一个最好的爬取数据的方法。所以只要我们掌握了这种思路就可以了哦!

练习-一键下电影-参考

第一步:分析问题,明确目标

我们想要实现这样的功能:用户输入喜欢的电影名字,程序即可在电影天堂(https://www.ygdy8.com)爬取电影所对应的下载链接,并将下载链接打印出来。

【讲解】

我们知道爬虫是模拟人在浏览器的动作批量获取有价值的信息,那对于这道题

,我们先手动操作下,看看人是如何实现这个过程的。

首先,打开电影天堂(https://www.ygdy8.com) , 在”搜索“处,填写一部电影名,以”无名之辈“为例,然后,我们进入了“搜索结果”页面,最后,在下载页面滑到最下方,找到了下载地址。

人工操作的步骤,我们是不是可以将其分为 “输名字 - 查搜索结果 - 进入下载页面 - 找到下载链接” ? 呐,我们就让我们的爬虫也这样子走就可以了对吧~

第二步:分析讲解

“输名字 - 查搜索结果 - 进入下载页面 - 找到下载链接”

我们是这样找到下载链接的,那只要让我们的爬虫也走这样的步骤, 就可以达成我们的目标啦

【讲解】

步骤一

“输名字”,学过基础课

的同学一定可以想到,用input()就可以啦。

步骤二

”搜索结果

页面“ 这里面涉及到一个坑,我们要一起填上。

输入不同的电影名,观察搜索结果页面的URL:

《无名之辈》的搜索结果URL:http://s.ygdy8.com/plus/s0.php?typeid=1&keyword=

%CE%DE%C3%FB%D6%AE%B1%B2

》的搜索结果URL:http://s.ygdy8.com/plus/s0.php?typeid=1&keyword=

%C9%F1%C6%E6%B6%AF%CE%EF

《狗十三》 的搜索结果URL:http://s.ygdy8.com/plus/s0.php?typeid=1&ke

yword=%B9%B7%CA%AE%C8%FD

观察URL,不难发现:http://s.ygdy8.com/plus/s0.php?typeid=1&keyword=() 这些都是一样的,只不过不同的电影名对应URL后面加了一些我们看不懂的字符

请阅读以下代码,注意注释哦:

选择语言
a= '无名之辈'
b= a.encode('gbk')
# 将汉字,用gbk格式编码,赋值给b
print(quote(b))

# quote()函数,可以帮我们把内容转为标准的url格式,作为网址的一部分打开

输出结果是:

%

CE%DE%C3%FB%D6%AE%B1%B2

记得在本地IDE上试着敲下哦,可以把'无名之辈’换成神奇

动物和狗十三,看看输出结果是否和对应的编码一致。

诶,发现的确是一致的,那我们一起来解读这段代码是怎么实现的呢。

注释中提到了gbk格式编码,那gbk是什么呢?

_GBK编码_ <br/>

GBK是中国标准,只在中国使用,并没有表示大多数其它国家的编码;

而各国又陆续推出各自的编码标准,互不兼容,非常不利于全球化发展。

于是后来国际组织发行了一个全球统一编码表,把全球各国文字都统一在一个编码标准里,名为Unicode。

由此我们知道,想把中文转换成url格式,需要先用encode('gbk')将其转成gbk编码,然

后再用quote()把它转化成url的一部分。

然后再将它与[http://s.ygdy8.com/plus/so.php?typeid=1&keywor

d=]()拼接起来就是电影的搜索结果页面啦~

好,总结下上面的这个知识点,如何建立“输入电影名”与“搜索结果页面”的联系:

__中文 - gbk - url - 拼接__

这样我们就把完整的搜索结果页面找到并提取出来了。<br>

步骤三 + 步骤四

”进入下载页面“ 与 “找到下载链接” 就是解析网页定位啦,利用find() 和 find_all(),都是你会的内容,加油呀~

第三步:书写代码吧 (。▰‿‿▰。) ❤

前两步我们已经捋顺了思路,还填了一个小坑,现在要自己敲代码咯,对转换格式编码的代码记不清的同学,可以偷偷看下提示哦。

【提示】

将汉字,用gbk格式编码,赋值,这时需要encode(),还需要用到quote()函数,可以帮我们把内

容转为标准的url格式,作为网址的一部分打开。

定位下载链接还是要用到find()哦~

有些电影没有下载链接,记得加个判断呀~

【解答】

选择语言
import requests
from bs4 import BeautifulSoup
from urllib.request import quote
#quote()函数,可以帮我们把内容转为标准的url格式,作为网址的一部分打开
movie = input('你想看什么电影呀?')
gbkmovie = movie.encode('gbk')
#将汉字,用gbk格式编码,赋值给gbkmovie
url = 'http://s.ygdy8.com/plus/s0.php?typeid=1&keyword='+quote(gbkmovie)
#将gbk格式的内容,转为url,然后和前半部分的网址拼接起来。
res = requests.get(url)
#下载××电影的搜索页面
res.encoding ='gbk'
#定义res的编码类型为gbk
soup_movie = BeautifulSoup(res.text,'html.parser')
#解析网页
urlpart = soup_movie.find(class_='co_content8').find_all('table')
if urlpart:
urlpart = urlpart[0].find('a')['href']
urlmovie = 'https://www.ygdy8.com/' + urlpart
res1 = requests.get(urlmovie)
res1.encoding = 'gbk'
soup_movie1 = BeautifulSoup(res1.text,'html.parser')
urldownload = soup_movie1.find('div',id='Zoom').find('span').find('table').find('a')['href']
print(urldownload)
else:
print('没有' + movie)
# 有些电影是查询不到没下载链接的,因此加了个判断

第5关

练习-歌词爬取-参考

第一步:分析问题,明确结果

问题需求就是把关卡内的代码稍作修改,将周杰伦前五页歌曲的歌词都爬取下来,结果就是全部展示打印出来。

【讲解】

问题需求就是把关卡内的代码稍作修改,将周杰伦前五页歌曲的歌词都爬取下来,结果就是全部展示打印出来。

第二步:写代码

【提示】

Network - XHR-client_search - Headers - Query String Parameters , 观察里面参数的变化

【解答】

https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=lyric&w=%E5%91%A8%E6%9D%B0%E4%BC%A6

爬取歌词这道题,有的同学找歌词的时候,会直接点进一首歌的详情页,然后打开“检查”,先在element去找,然后按照<div class='lyric_cont_box'>去定位

结果发现是爬取不到内容的





那爬不到的时候,我们就要去看看Network里面的内容

检查一下,ALL的第一个请求,是否网页的第0个请求里面是否有我们要抓取的内容?

操作如下,选择Network,选择ALL,刷新一下页面,选择第一个请求,名称是“004Fs2FP1EvZYc.html”





看看Preveiw的内容,好像没有我们想要的歌词内容也

那咋办?走!到XHR找找去

寻寻觅觅之后,发现了有这么一个请求,名称是:fcg_query_lyric_yqq.fcg......反正有个lyric(歌词的意思)

点开看看Preview的内容,果然有歌词





接下来,爬它!

既然是在XHR里面的内容,那爬取的方法就是:

用requests.get()去请求数据,请求数据后,需要用json()进行解析,解析完成后再按字典和列表的格式去提取数据

选择语言
import re,requests
lyric_url = 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_yqq.fcg'
headers = {
    'origin': 'https://y.qq.com',
    'referer': 'https://y.qq.com/n/yqq/song/004Fs2FP1EvZYc.html',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}
params = {
'nobase64': '1',
'musicid': '244115385',
'-': 'jsonp1',
'g_tk': '',
'loginUin': '0',
'hostUin': '0',
'format': 'json',
'inCharset': 'utf8',
'outCharset': 'utf-8',
'notice': '0',
'platform': 'yqq.json',
'needNewCode': '0'
}
res_lyric = requests.get(lyric_url,headers=headers,params=params)
json_lyric = res_lyric.json()
lyric = json_lyric['lyric']
print(lyric)

打印出来的结果如下:









爬是爬下来了,这也太乱七八糟了吧。助教有一种方法,把数据处理一下

在上面代码的最末尾,加上这么一段即可:

选择语言
for i in lyric.split('&#10'):
    music_str = re.sub('[A-Za-z0-9\\!\\%\\[\\]\\,\\。\\&\\#\\;]', '', i)#用正则表达式去掉无用的符号字符
    if music_str.strip():#strip去掉空行
        print(music_str)

简单地说一下这里用到的是“正则表达式”的知识,因为课堂里没有这个知识点的讲解,所以助教这里不做拓展哈~

到这里,我们确实爬取到了歌词的内容,但是,这样却只能爬取到一首歌的歌词啊。好像不符合题目要求也,那...我们是不是找错了?

嗯,也不是错,但是不太符合题目的要求

其实,题目原本希望我们去抓取的,是下面这个页面

在歌手的搜索页里,我们可以切换到“歌词”这一块的内容

同样我们先在ALL里面查看第0个请求





然后我们发现,数据依然不在这里。在这个html里面,是没有我们需要抓取的歌词内容信息的

也就是说,我们没有办法通过element去爬取歌词

下一步应该怎么做?

....(思考一下)

或许你已经想到了,我们就得从XHR里面去找了





如果没找到,那我们刷新一下页面,再用助教之前讲过的小技巧,给请求按Size排序来快速找到我们需要的请求。果然,client_search_cp 这个请求是最大的,排在最前面









既然是在XHR里面的内容,那再回忆一下爬取的方法:

1、requests.get()去请求数据,记得带上参数Params和Headers

2、请求数据后,需要用json()进行解析

3、解析完成后再按字典和列表的格式去提取数据

选择语言
import requests
import json
# 引用requests,json模块
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp'
headers = {
    'referer':'https://y.qq.com/portal/search.html',
    # 请求来源
    'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    # 标记了请求从什么设备,什么浏览器上发出
    }
for x in range(5):
    params = {
    'ct':'24',
    'qqmusic_ver': '1298',
    'new_json':'1',
    'remoteplace':'sizer.yqq.lyric_next',
    'searchid':'94267071827046963',
    'aggr':'1',
    'cr':'1',
    'catZhida':'1',
    'lossless':'0',
    'sem':'1',
    't':'7',
    'p':str(x+1),
    'n':'10',
    'w':'周杰伦',
    'g_tk':'1714057807',
    'loginUin':'0',
    'hostUin':'0',
    'format':'json',
    'inCharset':'utf8',
    'outCharset':'utf-8',
    'notice':'0',
    'platform':'yqq.json',
    'needNewCode':'0'  
    }   
    res = requests.get(url, params = params)
    #下载该网页,赋值给res
    jsonres = res.json()
    #使用json来解析res.text
    list_lyric = jsonres['data']['lyric']['list']
    #一层一层地取字典,获取歌词的列表
    for lyric in list_lyric:
    #lyric是一个列表,x是它里面的元素
        print(lyric['content'])
    #以content为键,查找歌词

果然,这样我们可以实现5个页面所有歌词的爬取了!

这个过程,也就是我们经过一番研究之后发现,从最初搜索结果的页面去爬取歌词是最方便简洁的

再补充一下,爬取歌词这个练习,第一次爬取下来的歌词呈现的效果如下









爬是爬下来了,怎么又太乱七八糟了吧。助教还有一种方法,把数据处理一下

解决方法:歌词里面\n其实是\\n来的,用字符串.replace('\\n','\n')就可以换行了,这是因为爬出来的歌词里面的\\n,然后打印的时候遇到\\n,会打印成\n

参考一下代码:

选择语言
    for lyric in list_lyric:
        print(lyric['content'].replace('\\n','\n'))

隐藏的终极版本:(电脑打开下载可看)

5关_歌词单曲页爬取.py2.9KB

练习-头条粉丝-参考

第一步: 阅读代码

作为头号粉丝,只爬取歌词不能满足迷妹迷弟们~我们还想要爬取自己喜欢的歌手音乐信息~

现在,请你阅读关卡内代码,思考应该如何修改它。

【提示】

阅读代码就可以了。

【讲解】

选择语言
import requests, json
#引用requests,json模块
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp'
for x in range(5):
params = {
'ct':'24',
'qqmusic_ver': '1298',
'new_json':'1',
'remoteplace':'txt.yqq.song',
'searchid':'70717568573156220',
't':'0',
'aggr':'1',
'cr':'1',
'catZhida':'1',
'lossless':'0',
'flag_qc':'0',
'p':str(x+1),
'n':'20',
'w':'周杰伦',
'g_tk':'714057807',
'loginUin':'0',
'hostUin':'0',
'format':'json',
'inCharset':'utf8',
'outCharset':'utf-8',
'notice':'0',
'platform':'yqq.json',
'needNewCode':'0'
}
# 将参数封装为字典
res_music = requests.get(url,params=params)
# 调用get方法,下载这个列表
json_music = res_music.json()
# 使用json()方法,将response对象,转为列表/字典
list_music = json_music['data']['song']['list']
# 一层一层地取字典,获取歌单列表
for music in list_music:
# list_music是一个列表,music是它里面的元素
print(music['name'])
# 以name为键,查找歌曲名
print('所属专辑:'+music['album']['name'])
# 查找专辑名
print('播放时长:'+str(music['interval'])+'秒')
# 查找播放时长
print('播放链接:https://y.qq.com/n/yqq/song/'+music['mid']+'.html\n\n')
# 查找播放链接

运行右侧代码发现我们只爬取到了周杰伦的歌曲信息,那么想做到一键换成任何喜欢的歌手该怎么做呢? 我们发现params里面的`w`对应的是歌手名字,那么我们就可以用input来替换掉呀~

第二步: 修改代码

作为头号粉丝,只爬取歌词不能满足迷妹迷弟们~我们还想要爬取自

己喜欢的歌手音乐信息~

现在,请你尝试修改代码。借助input()函数,实现爬取任意一个歌手的音乐信息。

【提示】

singer = input('你最喜欢的歌手是谁呀?')

【解答】

选择语言
import requests, json
# 引用requests模块
url = 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp'
singer = input('你喜欢的歌手是谁呢?')
for x in range(6):
params = {
'ct':'24',
'qqmusic_ver': '1298',
'new_json':'1',
'remoteplace':'txt.yqq.song',
'searchid':'70717568573156220',
't':'0',
'aggr':'1',
'cr':'1',
'catZhida':'1',
'lossless':'0',
'flag_qc':'0',
'p':str(x+1),
'n':'20',
'w':singer,
'g_tk':'714057807',
'loginUin':'0',
'hostUin':'0',
'format':'json',
'inCharset':'utf8',
'outCharset':'utf-8',
'notice':'0',
'platform':'yqq.json',
'needNewCode':'0'
}
# 将参数封装为字典
res_music = requests.get(url,params=params)
# 调用get方法,下载这个列表
json_music = res_music.json()
# 使用json()方法,将response对象,转为列表/字典
list_music = json_music['data']['song']['list']
# 一层一层地取字典,获取歌单列表
for music in list_music:
# list_music是一个列表,music是它里面的元素
print(music['name'])
# 以name为键,查找歌曲名
print('所属专辑:'+music['album']['name'])
# 查找专辑名
print('播放时长:'+str(music['interval'])+'秒')
# 查找播放时长
print('播放链接:https://y.qq.com/n/yqq/song/'+music['mid']+'.html\n\n')
# 查找播放链接

练习-一键查快递-参考

第一步:分析需求,明确目标

实现功能:用户输入快递名称和单号,程序即可在快递100(https://www.kuaidi100.com/)爬取最新物流状态,并将其打印出来。

【讲解】

先进入快递100(https://www.ku~如图,红框框里的是我们需要输入与想要提取的信息:

第二步:书写代码吧 (。▰‿‿▰。) ❤

如果没思路,可以偷偷看下提示哦~

【提示】

Network - query?type...  - Headers - Query String Parameters , 观察里面参数的变化~

服务器返回的内容,是json的格式。我们可以用处理列表、处理字典的手段来提取物流状态哦

【解答】

现在我们会发现根本查找不到正确的快递信息,这是因为快递一百增加了反爬虫,temp是系统随机参数,可以自己随机生成的,但是这个练习现在出不了正确的物流信息,所以现在当练习使用哦~后面第8关会讲到cookies的内容,到时可以再使用这个来做这个练习哈~

下面就是加上了cookies和randon的参考代码(需要自己更新一下cookies才有效哦):

选择语言
import requests
import random
#调用requests模块,负责上传和下载数据
cookie = input('请输入网页的cookie值')
kuaidiType = input('请输入快递类型(拼音)')
kuaidiID = input('请输入快递单号')
url = 'https://www.kuaidi100.com/query?'
#使用get需要一个链接
header = {
'Accept-Encoding': 'gzip, deflate, br',
'referer': 'https://www.kuaidi100.com/',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Connection': 'keep-alive',
'Cookie': cookie,
'Host': 'www.kuaidi100.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
a = random.random()
params = {
'type': kuaidiType,
'postid': kuaidiID,
'temp':str(a),
'phone':''
}
#将需要get的内容,以字典的形式记录在params内
r = requests.get(url, params=params,headers = header)
result = r.json()
for i in result['data']:
print(i['context'])
#记得观察preview里面的参数哦
(0)

相关推荐

    Database error: [You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1]

    select ID from ac_posts where ziID =  ;