0

MySQL DB から URL を取得し、それらの URL を start_urls として使用してスクレイピングするスパイダーがあり、スクレイピングされたページから任意の数の新しいリンクを取得します。start_url と新しいスクレイピングされた URL の両方を新しい DB に INSERT するようにパイプラインを設定した場合、または start_url を WHERE 基準として使用して、新しくスクレイピングされた URL で既存の DB を更新するようにパイプラインを設定した場合、SQL 構文エラーが発生します。

どちらか一方だけを挿入すると、エラーは発生しません。

これがspider.pyです

import scrapy
import MySQLdb
import MySQLdb.cursors
from scrapy.http.request import Request

from youtubephase2.items import Youtubephase2Item

class youtubephase2(scrapy.Spider):
    name = 'youtubephase2'

    def start_requests(self):
        conn = MySQLdb.connect(user='uname', passwd='password', db='YouTubeScrape', host='localhost', charset="utf8", use_unicode=True)
        cursor = conn.cursor()
        cursor.execute('SELECT resultURL FROM SearchResults;')
        rows = cursor.fetchall()

        for row in rows:
            if row:
                yield Request(row[0], self.parse, meta=dict(start_url=row[0]))
        cursor.close()

    def parse(self, response):
        for sel in response.xpath('//a[contains(@class, "yt-uix-servicelink")]'):
            item = Youtubephase2Item()
            item['newurl'] = sel.xpath('@href').extract()
            item['start_url'] = response.meta['start_url']
            yield item

これは、3 つの self.cursor.execute ステートメントすべてを示す pipeline.py です。

import MySQLdb
import MySQLdb.cursors
import hashlib
from scrapy import log
from scrapy.exceptions import DropItem
from twisted.enterprise import adbapi
from youtubephase2.items import Youtubephase2Item

class MySQLStorePipeline(object):
    def __init__(self):
        self.conn = MySQLdb.connect(user='uname', passwd='password', db='YouTubeScrape', host='localhost', charset="utf8", use_unicode=True)
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        try:

            #self.cursor.execute("""UPDATE SearchResults SET NewURL = %s WHERE ResultURL = %s VALUES (%s, %s)""",(item['newurl'], item['start_url']))
            #self.cursor.execute("""UPDATE SearchResults SET NewURL = %s WHERE ResultURL = %s""",(item['newurl'], item['start_url']))
            self.cursor.execute("""INSERT INTO TestResults (NewURL, StartURL) VALUES (%s, %s)""",(item['newurl'], item['start_url']))
            self.conn.commit()


        except MySQLdb.Error, e:
            log.msg("Error %d: %s" % (e.args[0], e.args[1]))

        return item

最上位の SQL 実行ステートメントは、次のエラーを返します。

2017-04-13 18:29:34 [scrapy.core.scraper] ERROR: Error processing {'newurl': [u'http://www.tagband.co.uk/'],
 'start_url': u'https://www.youtube.com/watch?v=UqguztfQPho'}
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 653, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/root/scraping/youtubephase2/youtubephase2/pipelines.py", line 18, in process_item
self.cursor.execute("""UPDATE SearchResults SET AffiliateURL = %s WHERE ResultURL = %s VALUES (%s, %s)""",(item['affiliateurl'], item['start_url']))
File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 159, in execute
query = query % db.literal(args)
TypeError: not enough arguments for format string

中間の SQL 実行ステートメントは、次のエラーを返します。

    2017-04-13 18:33:18 [scrapy.log] INFO: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') WHERE ResultURL = 'https://www.youtube.com/watch?v=UqguztfQPho'' at line 1
2017-04-13 18:33:18 [scrapy.core.scraper] DEBUG: Scraped from <200 https://www.youtube.com/watch?v=UqguztfQPho>
{'newurl': [u'http://www.tagband.co.uk/'],
 'start_url': u'https://www.youtube.com/watch?v=UqguztfQPho'}

最後の SQL 実行ステートメントは、新しいデータベースに INSERT を使用した場合でも、中間と同じエラーを返します。余分な一重引用符を追加するようです。最後の項目は、データベースにアイテムを 1 つだけ INSERT したときに機能します。

    2017-04-13 18:36:40 [scrapy.log] INFO: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '), 'https://www.youtube.com/watch?v=UqguztfQPho')' at line 1
2017-04-13 18:36:40 [scrapy.core.scraper] DEBUG: Scraped from <200 https://www.youtube.com/watch?v=UqguztfQPho>
{'newurl': [u'http://www.tagband.co.uk/'],
'start_url': u'https://www.youtube.com/watch?v=UqguztfQPho'}

長文すみません。徹底的にしようとしています。

4

1 に答える 1